Skip to content

Commit

Permalink
feat(technicalUser): add new delete logic
Browse files Browse the repository at this point in the history
Refs: #79
  • Loading branch information
Phil91 committed Oct 1, 2024
1 parent 347e187 commit 163b72d
Show file tree
Hide file tree
Showing 44 changed files with 1,450 additions and 361 deletions.
1 change: 0 additions & 1 deletion src/clients/Dim.Clients/Api/Dim/IDimClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

using Dim.Clients.Api.Dim.Models;
using Dim.Clients.Token;
using System.Text.Json;

namespace Dim.Clients.Api.Dim;

Expand Down
3 changes: 3 additions & 0 deletions src/clients/Dim.Clients/Api/Div/IProvisioningClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
********************************************************************************/

using Dim.Clients.Api.Div.Models;
using Dim.Clients.Token;

namespace Dim.Clients.Api.Div;

Expand All @@ -27,4 +28,6 @@ public interface IProvisioningClient
public Task<Guid> CreateOperation(Guid customerId, string customerName, string applicationName, string companyName, string didDocumentLocation, bool isIssuer, CancellationToken cancellationToken);
public Task<OperationResponse> GetOperation(Guid operationId, CancellationToken cancellationToken);
Task<Guid> CreateServiceKey(string technicalUserName, Guid walletId, CancellationToken cancellationToken);
Task<Guid?> DeleteServiceKey(Guid walletId, Guid serviceKeyId, CancellationToken cancellationToken);
Task<Guid> GetServiceKey(string technicalUserName, Guid walletId, CancellationToken cancellationToken);
}
42 changes: 42 additions & 0 deletions src/clients/Dim.Clients/Api/Div/Models/CustomerWalletsResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/********************************************************************************
* Copyright (c) 2024 BMW Group AG
* Copyright 2024 SAP SE or an SAP affiliate company and ssi-dim-middle-layer contributors.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using System.Text.Json.Serialization;

namespace Dim.Clients.Api.Div.Models;

public record CustomerWalletsResponse(
[property: JsonPropertyName("count")] int Count,
[property: JsonPropertyName("data")] IEnumerable<CustomerWallet> Data
);

public record CustomerWallet(
[property: JsonPropertyName("id")] Guid Id,
[property: JsonPropertyName("meteringId")] Guid MeteringId,
[property: JsonPropertyName("customerName")] string CustomerName,
[property: JsonPropertyName("customerId")] string CustomerId,
[property: JsonPropertyName("subscriptionUrl")] string SubscriptionUrl,
[property: JsonPropertyName("serviceKeys")] IEnumerable<CustomerServiceKey> ServiceKeys
);

public record CustomerServiceKey(
[property: JsonPropertyName("id")] Guid Id,
[property: JsonPropertyName("name")] string Name
);
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ public record TrustedIssuer(
[property: JsonPropertyName("ignoreMissingHashlist")] bool IgnoreMissingHashlist
);

public record CreateOperationRequest(
public record OperationRequest(
[property: JsonPropertyName("operationId")] Guid OperationId
);
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,21 @@ namespace Dim.Clients.Api.Div.Models;
public record ServiceKeyOperationCreationRequest(
[property: JsonPropertyName("entity")] string Entity,
[property: JsonPropertyName("action")] string Action,
[property: JsonPropertyName("payload")] ServiceKeyPayloadData Payload
[property: JsonPropertyName("payload")] ServiceKeyCreationPayloadData CreationPayload
);

public record ServiceKeyPayloadData(
public record ServiceKeyCreationPayloadData(
[property: JsonPropertyName("customerWalletId")] Guid CustomerWalletId,
[property: JsonPropertyName("divWalletServiceName")] string ServiceKeyName
);

public record ServiceKeyOperationDeletionRequest(
[property: JsonPropertyName("entity")] string Entity,
[property: JsonPropertyName("action")] string Action,
[property: JsonPropertyName("payload")] ServiceKeyDeletionPayloadData DeletionPayload
);

public record ServiceKeyDeletionPayloadData(
[property: JsonPropertyName("customerWalletKeyId")] Guid ServiceKeyId,
[property: JsonPropertyName("customerWalletId")] Guid CustomerWalletId
);
93 changes: 88 additions & 5 deletions src/clients/Dim.Clients/Api/Div/ProvisioningClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@

namespace Dim.Clients.Api.Div;

public class ProvisioningClient(IBasicAuthTokenService basicAuthTokenService, IOptions<ProvisioningSettings> settings) : IProvisioningClient
public class ProvisioningClient(IBasicAuthTokenService basicAuthTokenService, IOptions<ProvisioningSettings> options)
: IProvisioningClient
{
private readonly ProvisioningSettings _settings = settings.Value;
private readonly ProvisioningSettings _settings = options.Value;

public async Task<Guid> CreateOperation(Guid customerId, string customerName, string applicationName, string companyName, string didDocumentLocation, bool isIssuer, CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -79,7 +80,7 @@ [new ApplicationCompanyService("CredentialService", "https://dis-agent-prod.eu10
try
{
var response = await result.Content
.ReadFromJsonAsync<CreateOperationRequest>(JsonSerializerExtensions.Options, cancellationToken)
.ReadFromJsonAsync<OperationRequest>(JsonSerializerExtensions.Options, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);

if (response == null)
Expand Down Expand Up @@ -135,7 +136,7 @@ public async Task<Guid> CreateServiceKey(string technicalUserName, Guid walletId
var data = new ServiceKeyOperationCreationRequest(
"customer-wallet-key",
"create",
new ServiceKeyPayloadData(
new ServiceKeyCreationPayloadData(
walletId,
technicalUserName
)
Expand All @@ -154,7 +155,89 @@ public async Task<Guid> CreateServiceKey(string technicalUserName, Guid walletId
try
{
var response = await result.Content
.ReadFromJsonAsync<CreateOperationRequest>(JsonSerializerExtensions.Options, cancellationToken)
.ReadFromJsonAsync<OperationRequest>(JsonSerializerExtensions.Options, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);

if (response == null)
{
throw new ServiceException("response should never be null here");
}

return response.OperationId;
}
catch (JsonException je)
{
throw new ServiceException(je.Message);
}
}

public async Task<Guid> GetServiceKey(string technicalUserName, Guid walletId, CancellationToken cancellationToken)
{
var client = await basicAuthTokenService
.GetBasicAuthorizedClient<ProvisioningClient>(_settings, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
var result = await client.GetAsync($"/api/v1.0.0/customerWallets?CustomerWalletId={walletId}", cancellationToken)
.CatchingIntoServiceExceptionFor("get-service-key", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
async response =>
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(ConfigureAwaitOptions.None);
return (false, content);
}).ConfigureAwait(false);
try
{
var response = await result.Content
.ReadFromJsonAsync<CustomerWalletsResponse>(JsonSerializerExtensions.Options, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
if (response == null)
{
throw new ServiceException("Response must not be null");
}

var customers = response.Data.Where(x => x.Id == walletId);
if (customers.Count() != 1)
{
throw new ServiceException($"Must have exactly one customer for wallet id {walletId}");
}

var serviceKey = customers.Single().ServiceKeys.Where(sk => sk.Name.Equals(technicalUserName, StringComparison.OrdinalIgnoreCase));
if (serviceKey.Count() != 1)
{
throw new ServiceException($"Must have exactly one wallet and a service key with name {technicalUserName}");
}

return serviceKey.Single().Id;
}
catch (JsonException je)
{
throw new ServiceException(je.Message);
}
}

public async Task<Guid?> DeleteServiceKey(Guid walletId, Guid serviceKeyId, CancellationToken cancellationToken)
{
var data = new ServiceKeyOperationDeletionRequest(
"customer-wallet-key",
"delete",
new ServiceKeyDeletionPayloadData(
serviceKeyId,
walletId
)
);
var client = await basicAuthTokenService
.GetBasicAuthorizedClient<ProvisioningClient>(_settings, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);
var result = await client.PostAsJsonAsync("/api/v1.0.0/operations", data, JsonSerializerExtensions.Options, cancellationToken)
.CatchingIntoServiceExceptionFor("delete-service-key", HttpAsyncResponseMessageExtension.RecoverOptions.INFRASTRUCTURE,
async response =>
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(ConfigureAwaitOptions.None);
return (false, content);
})
.ConfigureAwait(false);
try
{
var response = await result.Content
.ReadFromJsonAsync<OperationRequest>(JsonSerializerExtensions.Options, cancellationToken)
.ConfigureAwait(ConfigureAwaitOptions.None);

if (response == null)
Expand Down
3 changes: 2 additions & 1 deletion src/database/Dim.DbAccess/DimRepositories.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class DimRepositories(DimDbContext dbContext)
{
private static readonly IReadOnlyDictionary<Type, Func<DimDbContext, object>> Types = new Dictionary<Type, Func<DimDbContext, object>> {
{ typeof(IProcessStepRepository), context => new ProcessStepRepository(context) },
{ typeof(ITenantRepository), context => new TenantRepository(context) }
{ typeof(ITenantRepository), context => new TenantRepository(context) },
{ typeof(ITechnicalUserRepository), context => new TechnicalUserRepository(context) }
}.ToImmutableDictionary();

public RepositoryType GetInstance<RepositoryType>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,5 @@ public interface IProcessStepRepository
void AttachAndModifyProcessSteps(IEnumerable<(Guid ProcessStepId, Action<ProcessStep>? Initialize, Action<ProcessStep> Modify)> processStepIdsInitializeModifyData);
IAsyncEnumerable<Process> GetActiveProcesses(IEnumerable<ProcessTypeId> processTypeIds, IEnumerable<ProcessStepTypeId> processStepTypeIds, DateTimeOffset lockExpiryDate);
IAsyncEnumerable<(Guid ProcessStepId, ProcessStepTypeId ProcessStepTypeId)> GetProcessStepData(Guid processId);
Task<ProcessData?> GetWalletProcessForTenant(string bpn, string companyName);
Task<ProcessData?> GetTechnicalUserProcess(string bpn, string companyName, string technicalUserName);
Task<(bool ProcessExists, VerifyProcessData ProcessData)> IsValidProcess(Guid processId, ProcessTypeId processTypeId, IEnumerable<ProcessStepTypeId> processSetpTypeIds);
}
40 changes: 40 additions & 0 deletions src/database/Dim.DbAccess/Repositories/ITechnicalUserRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/********************************************************************************
* Copyright (c) 2024 BMW Group AG
* Copyright 2024 SAP SE or an SAP affiliate company and ssi-dim-middle-layer contributors.
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using Dim.DbAccess.Models;
using Dim.Entities.Entities;

namespace Dim.DbAccess.Repositories;

public interface ITechnicalUserRepository
{
void CreateTenantTechnicalUser(Guid tenantId, string technicalUserName, Guid externalId, Guid processId);
void AttachAndModifyTechnicalUser(Guid technicalUserId, Action<TechnicalUser>? initialize, Action<TechnicalUser> modify);
Task<(bool Exists, Guid TechnicalUserId)> GetTenantDataForTechnicalUserProcessId(Guid processId);
Task<(Guid ExternalId, WalletData WalletData)> GetTechnicalUserCallbackData(Guid technicalUserId);
Task<(bool Exists, Guid TechnicalUserId, Guid ProcessId)> GetTechnicalUserForBpn(string bpn, string technicalUserName);
void RemoveTechnicalUser(Guid technicalUserId);
Task<(Guid? WalletId, string TechnicalUserName)> GetTechnicalUserNameAndWalletId(Guid technicalUserId);
Task<Guid?> GetOperationIdForTechnicalUser(Guid technicalUserId);
Task<(Guid? OperationId, Guid ExternalId)> GetOperationAndExternalIdForTechnicalUser(Guid technicalUserId);
Task<(Guid? ServiceKeyId, Guid? WalletId)> GetServiceKeyAndWalletId(Guid technicalUserId);
Task<ProcessData?> GetTechnicalUserProcess(string bpn, string companyName, string technicalUserName);
Task<(Guid? WalletId, string TechnicalUserName)> GetWalletIdAndNameForTechnicalUser(Guid technicalUserId);
}
10 changes: 1 addition & 9 deletions src/database/Dim.DbAccess/Repositories/ITenantRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,12 @@ public interface ITenantRepository
void AttachAndModifyTenant(Guid tenantId, Action<Tenant>? initialize, Action<Tenant> modify);
Task<(bool IsIssuer, string? HostingUrl)> GetHostingUrlAndIsIssuer(Guid tenantId);
Task<(bool Exists, Guid TenantId)> GetTenantForBpn(string bpn);
void CreateTenantTechnicalUser(Guid tenantId, string technicalUserName, Guid externalId, Guid processId);
void AttachAndModifyTechnicalUser(Guid technicalUserId, Action<TechnicalUser>? initialize, Action<TechnicalUser> modify);
Task<(bool Exists, Guid TechnicalUserId, string CompanyName, string Bpn)> GetTenantDataForTechnicalUserProcessId(Guid processId);
Task<(Guid ExternalId, WalletData WalletData)> GetTechnicalUserCallbackData(Guid technicalUserId);
Task<(bool Exists, Guid TechnicalUserId, Guid ProcessId)> GetTechnicalUserForBpn(string bpn, string technicalUserName);
Task<Guid> GetExternalIdForTechnicalUser(Guid technicalUserId);
void RemoveTechnicalUser(Guid technicalUserId);
Task<bool> IsTenantExisting(string companyName, string bpn);
Task<Guid?> GetOperationId(Guid tenantId);
Task<(string? BaseUrl, WalletData WalletData)> GetCompanyRequestData(Guid tenantId);
Task<(bool Exists, Guid? CompanyId, string? BaseUrl, WalletData WalletData)> GetCompanyAndWalletDataForBpn(string bpn);
Task<(Guid? CompanyId, string? BaseUrl, WalletData WalletData)> GetStatusListCreationData(Guid tenantId);
Task<(string Bpn, string? BaseUrl, WalletData WalletData, string? Did, string? DownloadUrl)> GetCallbackData(Guid tenantId);
Task<(string? DownloadUrl, bool IsIssuer)> GetDownloadUrlAndIsIssuer(Guid tenantId);
Task<(Guid? WalletId, string TechnicalUserName)> GetTechnicalUserNameAndWalletId(Guid technicalUserId);
Task<Guid?> GetOperationIdForTechnicalUser(Guid technicalUserId);
Task<ProcessData?> GetWalletProcessForTenant(string bpn, string companyName);
}
27 changes: 0 additions & 27 deletions src/database/Dim.DbAccess/Repositories/ProcessStepRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,33 +90,6 @@ public IAsyncEnumerable<Process> GetActiveProcesses(IEnumerable<ProcessTypeId> p
step.ProcessStepTypeId))
.AsAsyncEnumerable();

public Task<ProcessData?> GetWalletProcessForTenant(string bpn, string companyName) =>
dbContext.Tenants
.Where(x =>
x.Bpn == bpn &&
x.CompanyName == companyName &&
x.Process!.ProcessTypeId == ProcessTypeId.SETUP_DIM)
.Select(x => new ProcessData(
x.ProcessId,
x.Process!.ProcessSteps.Select(ps => new ProcessStepData(
ps.ProcessStepTypeId,
ps.ProcessStepStatusId))))
.SingleOrDefaultAsync();

public Task<ProcessData?> GetTechnicalUserProcess(string bpn, string companyName, string technicalUserName) =>
dbContext.TechnicalUsers
.Where(x =>
x.TechnicalUserName == technicalUserName &&
x.Tenant!.Bpn == bpn &&
x.Tenant!.CompanyName == companyName &&
x.Process!.ProcessTypeId == ProcessTypeId.TECHNICAL_USER)
.Select(x => new ProcessData(
x.ProcessId,
x.Process!.ProcessSteps.Select(ps => new ProcessStepData(
ps.ProcessStepTypeId,
ps.ProcessStepStatusId))))
.SingleOrDefaultAsync();

public Task<(bool ProcessExists, VerifyProcessData ProcessData)> IsValidProcess(Guid processId, ProcessTypeId processTypeId, IEnumerable<ProcessStepTypeId> processStepTypeIds) =>
dbContext.Processes
.AsNoTracking()
Expand Down
Loading

0 comments on commit 163b72d

Please sign in to comment.