diff --git a/src/credentials/SsiCredentialIssuer.Reissuance.App/Program.cs b/src/credentials/SsiCredentialIssuer.Reissuance.App/Program.cs index b4588a2c..d0e1edd1 100644 --- a/src/credentials/SsiCredentialIssuer.Reissuance.App/Program.cs +++ b/src/credentials/SsiCredentialIssuer.Reissuance.App/Program.cs @@ -30,7 +30,7 @@ using Org.Eclipse.TractusX.SsiCredentialIssuer.Portal.Service.DependencyInjection; LoggingExtensions.EnsureInitialized(); -Log.Information("Building worker"); +Log.Information("Building Reissuance App"); try { var host = Host @@ -47,7 +47,7 @@ }) .AddLogging() .Build(); - Log.Information("Building worker completed"); + Log.Information("Building Reissuance App completed"); using var tokenSource = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => diff --git a/src/database/SsiCredentialIssuer.DbAccess/Repositories/IReissuanceRepository.cs b/src/database/SsiCredentialIssuer.DbAccess/Repositories/IReissuanceRepository.cs index b2e469e9..1388a216 100644 --- a/src/database/SsiCredentialIssuer.DbAccess/Repositories/IReissuanceRepository.cs +++ b/src/database/SsiCredentialIssuer.DbAccess/Repositories/IReissuanceRepository.cs @@ -28,4 +28,6 @@ public interface IReissuanceRepository Guid GetCompanySsiDetailId(Guid companySsiDetaillId); bool IsReissuedCredential(Guid companySsiDetaillId); + + bool IsCredentialRevokedByReissuance(Guid companySsiDetaillId); } diff --git a/src/database/SsiCredentialIssuer.DbAccess/Repositories/ReissuanceRepository.cs b/src/database/SsiCredentialIssuer.DbAccess/Repositories/ReissuanceRepository.cs index 47427283..a4c9cc30 100644 --- a/src/database/SsiCredentialIssuer.DbAccess/Repositories/ReissuanceRepository.cs +++ b/src/database/SsiCredentialIssuer.DbAccess/Repositories/ReissuanceRepository.cs @@ -52,4 +52,11 @@ public bool IsReissuedCredential(Guid companySsiDetaillId) .Where(ssi => ssi.ReissuedCredentialId == companySsiDetaillId) .Select(ssi => true).SingleOrDefault(); } + + public bool IsCredentialRevokedByReissuance(Guid companySsiDetaillId) + { + return _dbContext.Reissuances + .Where(ssi => ssi.Id == companySsiDetaillId) + .Select(ssi => true).SingleOrDefault(); + } } diff --git a/src/database/SsiCredentialIssuer.Migrations/Seeder/Data/verified_credential_type_assigned_external_types.json b/src/database/SsiCredentialIssuer.Migrations/Seeder/Data/verified_credential_type_assigned_external_types.json index b4e48a92..cfa667b2 100644 --- a/src/database/SsiCredentialIssuer.Migrations/Seeder/Data/verified_credential_type_assigned_external_types.json +++ b/src/database/SsiCredentialIssuer.Migrations/Seeder/Data/verified_credential_type_assigned_external_types.json @@ -23,6 +23,10 @@ "verified_credential_external_type_id": 6, "verified_credential_type_id": 6 }, + { + "verified_credential_external_type_id": 7, + "verified_credential_type_id": 7 + }, { "verified_credential_external_type_id": 8, "verified_credential_type_id": 8 @@ -35,6 +39,10 @@ "verified_credential_external_type_id": 10, "verified_credential_type_id": 10 }, + { + "verified_credential_external_type_id": 11, + "verified_credential_type_id": 11 + }, { "verified_credential_external_type_id": 12, "verified_credential_type_id": 12 diff --git a/src/externalservices/Portal.Service/Models/NotificationTypeId.cs b/src/externalservices/Portal.Service/Models/NotificationTypeId.cs index e6d3409d..e334f8ca 100644 --- a/src/externalservices/Portal.Service/Models/NotificationTypeId.cs +++ b/src/externalservices/Portal.Service/Models/NotificationTypeId.cs @@ -152,5 +152,10 @@ public enum NotificationTypeId /// /// Notification when a credential got rejected /// - CREDENTIAL_EXPIRY = 26 + CREDENTIAL_EXPIRY = 26, + + /// + /// Notification when a credential got Reissued + /// + CREDENTIAL_RENEWAL = 27 } diff --git a/src/processes/CredentialProcess.Library/Expiry/CredentialExpiryProcessHandler.cs b/src/processes/CredentialProcess.Library/Expiry/CredentialExpiryProcessHandler.cs index 1660e571..3f0be8ed 100644 --- a/src/processes/CredentialProcess.Library/Expiry/CredentialExpiryProcessHandler.cs +++ b/src/processes/CredentialProcess.Library/Expiry/CredentialExpiryProcessHandler.cs @@ -83,10 +83,12 @@ public CredentialExpiryProcessHandler(IIssuerRepositories repositories, IWalletS public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> TriggerNotification(Guid credentialId, CancellationToken cancellationToken) { var (typeId, requesterId) = await _repositories.GetInstance().GetCredentialNotificationData(credentialId).ConfigureAwait(ConfigureAwaitOptions.None); + var notificationTypeId = await GetNotificationTypeId(credentialId); + if (Guid.TryParse(requesterId, out var companyUserId)) { var content = JsonSerializer.Serialize(new { Type = typeId, CredentialId = credentialId }, Options); - await _portalService.AddNotification(content, companyUserId, NotificationTypeId.CREDENTIAL_REJECTED, cancellationToken); + await _portalService.AddNotification(content, companyUserId, notificationTypeId, cancellationToken); } return ( @@ -96,18 +98,30 @@ public CredentialExpiryProcessHandler(IIssuerRepositories repositories, IWalletS null); } + private Task GetNotificationTypeId(Guid credentialId) + { + var isRevokedByReissuance = _repositories.GetInstance().IsCredentialRevokedByReissuance(credentialId); + return Task.FromResult(isRevokedByReissuance ? NotificationTypeId.CREDENTIAL_RENEWAL : NotificationTypeId.CREDENTIAL_REJECTED); + } + public async Task<(IEnumerable? nextStepTypeIds, ProcessStepStatusId stepStatusId, bool modified, string? processMessage)> TriggerMail(Guid credentialId, CancellationToken cancellationToken) { var (typeId, requesterId) = await _repositories.GetInstance().GetCredentialNotificationData(credentialId).ConfigureAwait(ConfigureAwaitOptions.None); - var typeValue = typeId.GetEnumValue() ?? throw new UnexpectedConditionException($"VerifiedCredentialType {typeId} does not exists"); + var isRevokedByReissuance = _repositories.GetInstance().IsCredentialRevokedByReissuance(credentialId); + if (Guid.TryParse(requesterId, out var companyUserId)) { - var mailParameters = new MailParameter[] + if (isRevokedByReissuance) + { + var mailParameters = CreateEmailParameters(typeValue, "The credential about to expiry is revoked and new credential was reissued"); + await _portalService.TriggerMail("CredentialRenewal", companyUserId, mailParameters, cancellationToken); + } + else { - new("requestName", typeValue), new("reason", "The credential is already expired") - }; - await _portalService.TriggerMail("CredentialRejected", companyUserId, mailParameters, cancellationToken); + var mailParameters = CreateEmailParameters(typeValue, "The credential is already expired"); + await _portalService.TriggerMail("CredentialRejected", companyUserId, mailParameters, cancellationToken); + } } return ( @@ -116,4 +130,12 @@ public CredentialExpiryProcessHandler(IIssuerRepositories repositories, IWalletS false, null); } + + private static MailParameter[] CreateEmailParameters(string typeValue, string reason) + { + return + [ + new("requestName", typeValue), new("reason", reason) + ]; + } } diff --git a/src/processes/CredentialProcess.Worker/DependencyInjection/CredentialProcessCollectionExtensions.cs b/src/processes/CredentialProcess.Worker/DependencyInjection/CredentialProcessCollectionExtensions.cs index f8c254a1..b6732f70 100644 --- a/src/processes/CredentialProcess.Worker/DependencyInjection/CredentialProcessCollectionExtensions.cs +++ b/src/processes/CredentialProcess.Worker/DependencyInjection/CredentialProcessCollectionExtensions.cs @@ -18,7 +18,6 @@ ********************************************************************************/ using Microsoft.Extensions.DependencyInjection; -using Org.Eclipse.TractusX.SsiCredentialIssuer.CredentialProcess.Library; using Org.Eclipse.TractusX.SsiCredentialIssuer.CredentialProcess.Library.DependencyInjection; using Org.Eclipse.TractusX.SsiCredentialIssuer.CredentialProcess.Worker.Expiry; using Org.Eclipse.TractusX.SsiCredentialIssuer.Processes.Worker.Library; diff --git a/tests/processes/CredentialProcess.Library.Tests/CredentialCreationProcessHandlerTests.cs b/tests/processes/CredentialProcess.Library.Tests/CredentialCreationProcessHandlerTests.cs index 57862757..c3da8b46 100644 --- a/tests/processes/CredentialProcess.Library.Tests/CredentialCreationProcessHandlerTests.cs +++ b/tests/processes/CredentialProcess.Library.Tests/CredentialCreationProcessHandlerTests.cs @@ -125,7 +125,7 @@ public async Task SignCredential_WithValidData_ReturnsExpected() result.modified.Should().BeFalse(); result.processMessage.Should().BeNull(); result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); - result.nextStepTypeIds.Should().ContainSingle().Which.Should().Be(ProcessStepTypeId.SAVE_CREDENTIAL_DOCUMENT); + result.nextStepTypeIds.Should().ContainSingle().Which.Should().Be(ProcessStepTypeId.REVOKE_REISSUED_CREDENTIAL); } #endregion diff --git a/tests/processes/CredentialProcess.Library.Tests/CredentialExpiryProcessHandlerTests.cs b/tests/processes/CredentialProcess.Library.Tests/CredentialExpiryProcessHandlerTests.cs index 56f95cb7..1155ee66 100644 --- a/tests/processes/CredentialProcess.Library.Tests/CredentialExpiryProcessHandlerTests.cs +++ b/tests/processes/CredentialProcess.Library.Tests/CredentialExpiryProcessHandlerTests.cs @@ -42,6 +42,7 @@ public class CredentialExpiryProcessHandlerTests private readonly IWalletService _walletService; private readonly IIssuerRepositories _issuerRepositories; private readonly ICredentialRepository _credentialRepository; + private readonly IReissuanceRepository _reissuanceRepository; private readonly IPortalService _portalService; private readonly CredentialExpiryProcessHandler _sut; @@ -58,9 +59,11 @@ public CredentialExpiryProcessHandlerTests() _issuerRepositories = A.Fake(); _credentialRepository = A.Fake(); _documentRepository = A.Fake(); + _reissuanceRepository = A.Fake(); A.CallTo(() => _issuerRepositories.GetInstance()).Returns(_credentialRepository); A.CallTo(() => _issuerRepositories.GetInstance()).Returns(_documentRepository); + A.CallTo(() => _issuerRepositories.GetInstance()).Returns(_reissuanceRepository); _walletService = A.Fake(); _portalService = A.Fake(); @@ -162,7 +165,7 @@ public async Task RevokeCredential_WithEmptyExternalCredentialId_ThrowsConflictE #region TriggerNotification [Fact] - public async Task TriggerNotification_WithValid_CallsExpected() + public async Task TriggerNotification_CredentialRejected_WithValid_CallsExpected() { // Arrange var requesterId = Guid.NewGuid(); @@ -181,12 +184,32 @@ public async Task TriggerNotification_WithValid_CallsExpected() result.nextStepTypeIds.Should().ContainSingle().Which.Should().Be(ProcessStepTypeId.TRIGGER_MAIL); } + [Fact] + public async Task TriggerNotification_CredentialRenewal_WithValid_CallsExpected() + { + // Arrange + var requesterId = Guid.NewGuid(); + A.CallTo(() => _reissuanceRepository.IsCredentialRevokedByReissuance(_credentialId)).Returns(true); + A.CallTo(() => _credentialRepository.GetCredentialNotificationData(_credentialId)) + .Returns((VerifiedCredentialExternalTypeId.BUSINESS_PARTNER_NUMBER, requesterId.ToString())); + + // Act + var result = await _sut.TriggerNotification(_credentialId, CancellationToken.None); + + // Assert + A.CallTo(() => _portalService.AddNotification(A._, requesterId, NotificationTypeId.CREDENTIAL_RENEWAL, A._)) + .MustHaveHappenedOnceExactly(); + result.modified.Should().BeFalse(); + result.processMessage.Should().BeNull(); + result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); + result.nextStepTypeIds.Should().ContainSingle().Which.Should().Be(ProcessStepTypeId.TRIGGER_MAIL); + } #endregion #region TriggerMail [Fact] - public async Task TriggerMail_WithValid_CallsExpected() + public async Task TriggerMail_CredentialRejected_WithValid_CallsExpected() { // Arrange var requesterId = Guid.NewGuid(); @@ -205,5 +228,25 @@ public async Task TriggerMail_WithValid_CallsExpected() result.nextStepTypeIds.Should().BeNull(); } + [Fact] + public async Task TriggerMail_CredentialRenewal_WithValid_CallsExpected() + { + // Arrange + var requesterId = Guid.NewGuid(); + A.CallTo(() => _reissuanceRepository.IsCredentialRevokedByReissuance(_credentialId)).Returns(true); + A.CallTo(() => _credentialRepository.GetCredentialNotificationData(_credentialId)) + .Returns((VerifiedCredentialExternalTypeId.MEMBERSHIP_CREDENTIAL, requesterId.ToString())); + + // Act + var result = await _sut.TriggerMail(_credentialId, CancellationToken.None); + + // Assert + A.CallTo(() => _portalService.TriggerMail("CredentialRenewal", requesterId, A>._, A._)) + .MustHaveHappenedOnceExactly(); + result.modified.Should().BeFalse(); + result.processMessage.Should().BeNull(); + result.stepStatusId.Should().Be(ProcessStepStatusId.DONE); + result.nextStepTypeIds.Should().BeNull(); + } #endregion }