Skip to content

Commit

Permalink
Merge pull request #1038 from Energinet-DataHub/xvibe/move-grid-areas…
Browse files Browse the repository at this point in the history
…-to-actor

Consolidate Actor service
  • Loading branch information
vbelinschi authored Dec 4, 2024
2 parents 2842a39 + f960fbf commit 274c9db
Show file tree
Hide file tree
Showing 16 changed files with 678 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using System.Threading;
using System.Threading.Tasks;
using Energinet.DataHub.MarketParticipant.Application.Commands.Actors;
using Energinet.DataHub.MarketParticipant.Application.Services;
using Energinet.DataHub.MarketParticipant.Domain;
using Energinet.DataHub.MarketParticipant.Domain.Repositories;
using MediatR;
Expand All @@ -27,15 +28,18 @@ public sealed class ConsolidateActorsHandler : IRequestHandler<ConsolidateActors
private readonly IActorConsolidationRepository _actorConsolidationRepository;
private readonly IDomainEventRepository _domainEventRepository;
private readonly IUnitOfWorkProvider _unitOfWorkProvider;
private readonly IActorConsolidationService _actorConsolidationService;

public ConsolidateActorsHandler(
IActorConsolidationRepository actorConsolidationRepository,
IDomainEventRepository domainEventRepository,
IUnitOfWorkProvider unitOfWorkProvider)
IUnitOfWorkProvider unitOfWorkProvider,
IActorConsolidationService actorConsolidationService)
{
_actorConsolidationRepository = actorConsolidationRepository;
_domainEventRepository = domainEventRepository;
_unitOfWorkProvider = unitOfWorkProvider;
_actorConsolidationService = actorConsolidationService;
}

public async Task Handle(ConsolidateActorsCommand request, CancellationToken cancellationToken)
Expand All @@ -53,6 +57,11 @@ public async Task Handle(ConsolidateActorsCommand request, CancellationToken can
.ConfigureAwait(false);

// Do consolidation here
foreach (var actorConsolidation in actorsReadyToConsolidate)
{
await _actorConsolidationService.ConsolidateAsync(actorConsolidation).ConfigureAwait(false);
}

// Send domain event here
await uow.CommitAsync().ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,27 @@
using Energinet.DataHub.MarketParticipant.Domain.Exception;
using Energinet.DataHub.MarketParticipant.Domain.Model;
using Energinet.DataHub.MarketParticipant.Domain.Repositories;
using Energinet.DataHub.MarketParticipant.Domain.Services;
using MediatR;

namespace Energinet.DataHub.MarketParticipant.Application.Handlers.Actors;

public sealed class RemoveActorCredentialsHandler : IRequestHandler<RemoveActorCredentialsCommand>
{
private readonly IActorRepository _actorRepository;
private readonly ICertificateService _certificateService;
private readonly IUnitOfWorkProvider _unitOfWorkProvider;
private readonly IDomainEventRepository _domainEventRepository;
private readonly IActorClientSecretService _actorClientSecretService;
private readonly IActorCredentialsRemovalService _actorCredentialsRemovalService;

public RemoveActorCredentialsHandler(
IActorRepository actorRepository,
ICertificateService certificateService,
IUnitOfWorkProvider unitOfWorkProvider,
IDomainEventRepository domainEventRepository,
IActorClientSecretService actorClientSecretService)
IActorCredentialsRemovalService actorCredentialsRemovalService)
{
_actorRepository = actorRepository;
_certificateService = certificateService;
_unitOfWorkProvider = unitOfWorkProvider;
_domainEventRepository = domainEventRepository;
_actorClientSecretService = actorClientSecretService;
_actorCredentialsRemovalService = actorCredentialsRemovalService;
}

public async Task Handle(RemoveActorCredentialsCommand request, CancellationToken cancellationToken)
Expand All @@ -58,22 +54,7 @@ public async Task Handle(RemoveActorCredentialsCommand request, CancellationToke

NotFoundValidationException.ThrowIfNull(actor, request.ActorId);

if (actor.Credentials is null)
return;

switch (actor.Credentials)
{
case ActorCertificateCredentials certificateCredentials:
await _certificateService.RemoveCertificateAsync(certificateCredentials.KeyVaultSecretIdentifier).ConfigureAwait(false);
break;
case ActorClientSecretCredentials when actor.ExternalActorId is not null:
await _actorClientSecretService.RemoveSecretAsync(actor).ConfigureAwait(false);
break;
default:
throw new InvalidOperationException($"Actor with id {request.ActorId} does not have a known type of credentials assigned");
}

actor.Credentials = null;
await _actorCredentialsRemovalService.RemoveActorCredentialsAsync(actor).ConfigureAwait(false);

var uow = await _unitOfWorkProvider
.NewUnitOfWorkAsync()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Energinet.DataHub.MarketParticipant.Domain.Exception;
using Energinet.DataHub.MarketParticipant.Domain.Model;
using Energinet.DataHub.MarketParticipant.Domain.Repositories;
using NodaTime;

namespace Energinet.DataHub.MarketParticipant.Application.Services;

public sealed class ActorConsolidationService : IActorConsolidationService
{
private readonly IActorConsolidationAuditLogRepository _actorConsolidationAuditLogRepository;
private readonly IActorCredentialsRemovalService _actorCredentialsRemovalService;
private readonly IActorRepository _actorRepository;
private readonly IAuditIdentityProvider _auditIdentityProvider;
private readonly IDomainEventRepository _domainEventRepository;
private readonly IGridAreaRepository _gridAreaRepository;

public ActorConsolidationService(
IActorConsolidationAuditLogRepository actorConsolidationAuditLogRepository,
IActorCredentialsRemovalService actorCredentialsRemovalService,
IActorRepository actorRepository,
IAuditIdentityProvider auditIdentityProvider,
IDomainEventRepository domainEventRepository,
IGridAreaRepository gridAreaRepository)
{
_actorConsolidationAuditLogRepository = actorConsolidationAuditLogRepository;
_actorCredentialsRemovalService = actorCredentialsRemovalService;
_actorRepository = actorRepository;
_auditIdentityProvider = auditIdentityProvider;
_domainEventRepository = domainEventRepository;
_gridAreaRepository = gridAreaRepository;
}

public async Task ConsolidateAsync(ActorConsolidation actorConsolidation)
{
ArgumentNullException.ThrowIfNull(actorConsolidation);

var fromActor = await _actorRepository.GetAsync(actorConsolidation.ActorFromId).ConfigureAwait(false);
NotFoundValidationException.ThrowIfNull(fromActor, actorConsolidation.ActorFromId.Value);

var toActor = await _actorRepository.GetAsync(actorConsolidation.ActorToId).ConfigureAwait(false);
NotFoundValidationException.ThrowIfNull(toActor, actorConsolidation.ActorToId.Value);

if (fromActor.MarketRole.Function is EicFunction.GridAccessProvider
&& toActor.MarketRole.Function is EicFunction.GridAccessProvider)
{
var actorGridAreasToTransfer = fromActor.MarketRole.GridAreas.ToList();

toActor.TransferGridAreasFrom(fromActor);

await UpdateGridAreasValidToDateAsync(actorGridAreasToTransfer, actorConsolidation.ConsolidateAt).ConfigureAwait(false);
await AuditLogConsolidationCompletedAsync(actorGridAreasToTransfer, actorConsolidation).ConfigureAwait(false);
}

await DeactivateActorAsync(fromActor).ConfigureAwait(false);

await _actorRepository
.AddOrUpdateAsync(fromActor)
.ConfigureAwait(false);

await _actorRepository
.AddOrUpdateAsync(toActor)
.ConfigureAwait(false);

await _domainEventRepository
.EnqueueAsync(fromActor)
.ConfigureAwait(false);

await _domainEventRepository
.EnqueueAsync(toActor)
.ConfigureAwait(false);
}

private async Task AuditLogConsolidationCompletedAsync(
IEnumerable<ActorGridArea> actorGridAreas,
ActorConsolidation actorConsolidation)
{
foreach (var actorGridArea in actorGridAreas)
{
await _actorConsolidationAuditLogRepository.AuditAsync(
_auditIdentityProvider.IdentityId,
GridAreaAuditedChange.ConsolidationCompleted,
actorConsolidation,
actorGridArea.Id).ConfigureAwait(false);
}
}

private async Task DeactivateActorAsync(Actor actor)
{
await _actorCredentialsRemovalService.RemoveActorCredentialsAsync(actor).ConfigureAwait(false);
actor.Deactivate();
}

private async Task UpdateGridAreasValidToDateAsync(ICollection<ActorGridArea> actorGridAreasToTransfer, Instant scheduledAt)
{
var allGridAreas = await _gridAreaRepository.GetAsync().ConfigureAwait(false);
var gridAreasToUpdate = allGridAreas.Where(ga => actorGridAreasToTransfer.Select(aga => aga.Id).Contains(ga.Id));
foreach (var gridArea in gridAreasToUpdate)
{
gridArea.ValidTo = scheduledAt.ToDateTimeOffset();
await _gridAreaRepository
.AddOrUpdateAsync(gridArea)
.ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Threading.Tasks;
using Energinet.DataHub.MarketParticipant.Domain.Model;
using Energinet.DataHub.MarketParticipant.Domain.Services;

namespace Energinet.DataHub.MarketParticipant.Application.Services;

public sealed class ActorCredentialsRemovalService : IActorCredentialsRemovalService
{
private readonly ICertificateService _certificateService;
private readonly IActorClientSecretService _actorClientSecretService;

public ActorCredentialsRemovalService(ICertificateService certificateService, IActorClientSecretService actorClientSecretService)
{
_certificateService = certificateService;
_actorClientSecretService = actorClientSecretService;
}

public async Task RemoveActorCredentialsAsync(Actor actor)
{
ArgumentNullException.ThrowIfNull(actor);
if (actor.Credentials is null)
return;

switch (actor.Credentials)
{
case ActorCertificateCredentials certificateCredentials:
await _certificateService.RemoveCertificateAsync(certificateCredentials.KeyVaultSecretIdentifier).ConfigureAwait(false);
break;
case ActorClientSecretCredentials when actor.ExternalActorId is not null:
await _actorClientSecretService.RemoveSecretAsync(actor).ConfigureAwait(false);
break;
default:
throw new InvalidOperationException($"Actor with id {actor.Id} does not have a known type of credentials assigned");
}

actor.Credentials = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Threading.Tasks;
using Energinet.DataHub.MarketParticipant.Domain.Model;

namespace Energinet.DataHub.MarketParticipant.Application.Services;

public interface IActorConsolidationService
{
Task ConsolidateAsync(ActorConsolidation actorConsolidation);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2020 Energinet DataHub A/S
//
// Licensed under the Apache License, Version 2.0 (the "License2");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System.Threading.Tasks;
using Energinet.DataHub.MarketParticipant.Domain.Model;

namespace Energinet.DataHub.MarketParticipant.Application.Services;

public interface IActorCredentialsRemovalService
{
Task RemoveActorCredentialsAsync(Actor actor);
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,5 +127,7 @@ public static void AddApplicationServices(this IServiceCollection services)
services.AddScoped<ICertificateValidation, NoCertificateValidation>();
services.AddScoped<IPermissionRelationService, PermissionRelationService>();
services.AddScoped<IBalanceResponsiblePartiesChangedEventHandler, BalanceResponsiblePartiesChangedEventHandler>();
services.AddScoped<IActorConsolidationService, ActorConsolidationService>();
services.AddScoped<IActorCredentialsRemovalService, ActorCredentialsRemovalService>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,5 @@ public static void AddRepositories(this IServiceCollection services)
services.AddScoped<IDownloadTokenRespository, DownloadTokenRespository>();
services.AddScoped<IB2CLogRepository, B2CLogRepository>();
services.AddScoped<ICutoffRepository, CutoffRepository>();
services.AddScoped<IActorConsolidationRepository, ActorConsolidationRepository>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Energinet.DataHub.MarketParticipant.Domain.Exception;
using Energinet.DataHub.MarketParticipant.Domain.Model.Events;

Expand Down Expand Up @@ -231,4 +232,30 @@ public void Deactivate()
/// Only Active and New actors can be set to passive.
/// </summary>
public void SetAsPassive() => _actorStatusTransitioner.SetAsPassive();

public void TransferGridAreasFrom(Actor fromActor)
{
ArgumentNullException.ThrowIfNull(fromActor);

if (_actorStatusTransitioner.Status is ActorStatus.Active or ActorStatus.Passive)
{
foreach (var actorGridArea in fromActor.MarketRole.GridAreas)
{
_domainEvents.Add(new GridAreaOwnershipAssigned(
ActorNumber,
MarketRole.Function,
actorGridArea.Id));
}
}

MarketRole = new ActorMarketRole(
MarketRole.Function,
MarketRole.GridAreas.Concat(fromActor.MarketRole.GridAreas),
MarketRole.Comment);

fromActor.MarketRole = new ActorMarketRole(
MarketRole.Function,
[],
MarketRole.Comment);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ public async Task<Instant> GetCutoffAsync(CutoffType type)
{
var cutoff = await _context.Cutoffs.SingleOrDefaultAsync(x => x.Type == (int)type).ConfigureAwait(false);

if (cutoff == null)
{
cutoff = await InsertCutoffAsync(type, Instant.FromUnixTimeTicks(0)).ConfigureAwait(false);
}
cutoff ??= await InsertCutoffAsync(type, Instant.FromUnixTimeTicks(0)).ConfigureAwait(false);

return cutoff.Timestamp.ToInstant();
}
Expand Down
Loading

0 comments on commit 274c9db

Please sign in to comment.