Skip to content

Commit

Permalink
fix(App&Service)! : email notification fix for offerSubscriptions (#239)
Browse files Browse the repository at this point in the history
* fix(App&Service)! : email notification fix for
offerSubscriptions
* added mail service
* chore: Added SubscriptionMangerRoles in
IntegrationTests.json files
* chore: adjust and extend unit-tests
CPLP-3111
---------
Co-authored-by: Norbert Truchsess <[email protected]>
Reviewed-By: Norbert Truchsess <[email protected]>
  • Loading branch information
VPrasannaK94 authored Sep 11, 2023
1 parent fcef047 commit 5ae0519
Show file tree
Hide file tree
Showing 27 changed files with 679 additions and 99 deletions.
30 changes: 30 additions & 0 deletions src/Portal.Backend.sln
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keycloak.Seeding", "keycloa
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Keycloak.Seeding.Tests", "..\tests\keycloak\Keycloak.Seeding.Tests\Keycloak.Seeding.Tests.csproj", "{A5BEDD89-7280-466E-8D14-EC5E177AAD07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailing.Service", "mailing\Mailing.Service\Mailing.Service.csproj", "{6113B579-C995-47F8-9AC1-4CC6EFDDD883}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mailing.Service.Tests", "..\tests\mailing\Mailing.Service.Tests\Mailing.Service.Tests.csproj", "{1EAF34DA-6D16-4F5E-86F4-344185F53942}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1340,6 +1344,30 @@ Global
{A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x64.Build.0 = Release|Any CPU
{A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x86.ActiveCfg = Release|Any CPU
{A5BEDD89-7280-466E-8D14-EC5E177AAD07}.Release|x86.Build.0 = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x64.ActiveCfg = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x64.Build.0 = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x86.ActiveCfg = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Debug|x86.Build.0 = Debug|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|Any CPU.Build.0 = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x64.ActiveCfg = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x64.Build.0 = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x86.ActiveCfg = Release|Any CPU
{6113B579-C995-47F8-9AC1-4CC6EFDDD883}.Release|x86.Build.0 = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x64.ActiveCfg = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x64.Build.0 = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x86.ActiveCfg = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Debug|x86.Build.0 = Debug|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|Any CPU.Build.0 = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x64.ActiveCfg = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x64.Build.0 = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x86.ActiveCfg = Release|Any CPU
{1EAF34DA-6D16-4F5E-86F4-344185F53942}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -1348,6 +1376,7 @@ Global
SolutionGuid = {2EB6265F-323A-4BF3-969E-003D64A14B64}
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1EAF34DA-6D16-4F5E-86F4-344185F53942} = {323C198D-A8C6-4EB0-8B79-72624275E35F}
{A5BEDD89-7280-466E-8D14-EC5E177AAD07} = {323C198D-A8C6-4EB0-8B79-72624275E35F}
{EA9BA26E-83F6-47C4-BA3B-880AF1AD6A82} = {323C198D-A8C6-4EB0-8B79-72624275E35F}
{4B40193E-2C67-4DC4-8EF4-3286DAA01D8B} = {323C198D-A8C6-4EB0-8B79-72624275E35F}
Expand Down Expand Up @@ -1441,5 +1470,6 @@ Global
{47E089E3-E875-4045-9E58-C1223BE899E9} = {23500169-FC01-4D2B-A997-E7FAE2169FC0}
{9D574E57-75A6-4965-AF23-ACE0BB9CD0B3} = {323C198D-A8C6-4EB0-8B79-72624275E35F}
{E1D41A07-F468-4D13-8185-35F127230B17} = {46383371-8252-4598-9350-A97692851408}
{6113B579-C995-47F8-9AC1-4CC6EFDDD883} = {68D43DB1-DFC5-4F15-A2B4-6BA18B875F9E}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Microsoft.Extensions.DependencyInjection;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service;

namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service.DependencyInjection;

public static class MailingServiceExtensions
{
public static IServiceCollection AddMailingService(this IServiceCollection services)
{
return services
.AddTransient<IRoleBaseMailService, RoleBaseMailService>();
}
}
28 changes: 28 additions & 0 deletions src/mailing/Mailing.Service/IRoleBaseMailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/********************************************************************************
* Copyright (c) 2021, 2023 BMW Group AG
* Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
*
* 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 Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;

namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service;

public interface IRoleBaseMailService
{
Task RoleBaseSendMail(IEnumerable<UserRoleConfig> receiverRoles, IEnumerable<(string ParameterName, string ParameterValue)> parameters, (string ParameterName, string ParameterValue)? userNameParameter, IEnumerable<string> template, Guid companyId);
}
33 changes: 33 additions & 0 deletions src/mailing/Mailing.Service/Mailing.Service.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
- Copyright (c) 2021, 2023 BMW Group AG
- Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
-
- 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
-->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\..\portalbackend\PortalBackend.DBAccess\PortalBackend.DBAccess.csproj" />
<ProjectReference Include="..\..\portalbackend\PortalBackend.PortalEntities\PortalBackend.PortalEntities.csproj" />
<ProjectReference Include="..\..\framework\Framework.Models\Framework.Models.csproj" />
<ProjectReference Include="..\Mailing.SendMail\Mailing.SendMail.csproj" />
</ItemGroup>
<PropertyGroup>
<AssemblyName>Org.Eclipse.TractusX.Portal.Backend.Mailing.Service</AssemblyName>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
76 changes: 76 additions & 0 deletions src/mailing/Mailing.Service/RoleBaseMailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/********************************************************************************
* Copyright (c) 2021, 2023 BMW Group AG
* Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation
*
* 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 Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Repositories;
using System.Collections.Immutable;

namespace Org.Eclipse.TractusX.Portal.Backend.Mailing.Service;

public class RoleBaseMailService : IRoleBaseMailService
{

private readonly IPortalRepositories _portalRepositories;
private readonly IMailingService _mailingService;

public RoleBaseMailService(IPortalRepositories portalRepositories, IMailingService mailingService)
{
_portalRepositories = portalRepositories;
_mailingService = mailingService;
}
public async Task RoleBaseSendMail(IEnumerable<UserRoleConfig> receiverRoles, IEnumerable<(string ParameterName, string ParameterValue)> parameters, (string ParameterName, string ParameterValue)? userNameParameter, IEnumerable<string> template, Guid companyId)
{
var receiverUserRoles = receiverRoles;
var userRolesRepository = _portalRepositories.GetInstance<IUserRolesRepository>();
var roleData = await userRolesRepository
.GetUserRoleIdsUntrackedAsync(receiverUserRoles)
.ToListAsync()
.ConfigureAwait(false);
if (roleData.Count < receiverUserRoles.Sum(clientRoles => clientRoles.UserRoleNames.Count()))
{
throw new ConfigurationException(
$"invalid configuration, at least one of the configured roles does not exist in the database: {string.Join(", ", receiverUserRoles.Select(clientRoles => $"client: {clientRoles.ClientId}, roles: [{string.Join(", ", clientRoles.UserRoleNames)}]"))}");
}

var companyUserWithRoleIdForCompany = _portalRepositories.GetInstance<IUserRepository>()
.GetCompanyUserEmailForCompanyAndRoleId(roleData, companyId);

await foreach (var (receiver, firstName, lastName) in companyUserWithRoleIdForCompany)
{
IEnumerable<(string ParameterName, string ParameterValue)> ParametersWithUserName()
{
if (userNameParameter.HasValue)
{
var userName = string.Join(" ", new[] { firstName, lastName }.Where(item => !string.IsNullOrWhiteSpace(item)));
return parameters.Append(
string.IsNullOrWhiteSpace(userName)
? userNameParameter.Value
: new(userNameParameter.Value.ParameterName, userName));
}
return parameters;
}

await _mailingService.SendMails(receiver, ParametersWithUserName().ToImmutableDictionary(x => x.ParameterName, x => x.ParameterValue), template).ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public async Task AddFavouriteAppForUserAsync(Guid appId, Guid userId)

/// <inheritdoc/>
public Task<Guid> AddOwnCompanyAppSubscriptionAsync(Guid appId, IEnumerable<OfferAgreementConsentData> offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity) =>
_offerSubscriptionService.AddOfferSubscriptionAsync(appId, offerAgreementConsentData, identity, OfferTypeId.APP, _settings.BasePortalAddress);
_offerSubscriptionService.AddOfferSubscriptionAsync(appId, offerAgreementConsentData, identity, OfferTypeId.APP, _settings.BasePortalAddress, _settings.SubscriptionManagerRoles);

/// <inheritdoc/>
public async Task ActivateOwnCompanyProvidedAppSubscriptionAsync(Guid subscriptionId, (Guid UserId, Guid CompanyId) identity)
Expand Down
7 changes: 7 additions & 0 deletions src/marketplace/Apps.Service/BusinessLogic/AppsSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ public class AppsSettings
[Required]
[DistinctValues("x => x.ClientId")]
public IEnumerable<UserRoleConfig> CompanyAdminRoles { get; set; } = null!;

/// <summary>
/// Roles to notify when a new subscription was created
/// </summary>
[Required]
[DistinctValues("x => x.ClientId")]
public IEnumerable<UserRoleConfig> SubscriptionManagerRoles { get; set; } = null!;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

using Microsoft.Extensions.DependencyInjection;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Logging;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service;
using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Service;
using Org.Eclipse.TractusX.Portal.Backend.Processes.OfferSubscription.Library.DependencyInjection;

Expand All @@ -35,6 +36,7 @@ public static IServiceCollection AddOfferServices(this IServiceCollection servic
return services
.AddTransient<IOfferService, OfferService>()
.AddTransient<IOfferSetupService, OfferSetupService>()
.AddTransient<IRoleBaseMailService, RoleBaseMailService>()
.AddTransient<IOfferSubscriptionService, OfferSubscriptionService>()
.AddOfferSubscriptionProcess();
}
Expand Down
1 change: 1 addition & 0 deletions src/marketplace/Offers.Library/Offers.Library.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<ProjectReference Include="..\..\notifications\Notifications.Library\Notifications.Library.csproj" />
<ProjectReference Include="..\..\processes\OfferSubscription.Library\OfferSubscription.Library.csproj" />
<ProjectReference Include="..\..\provisioning\Provisioning.Library\Provisioning.Library.csproj" />
<ProjectReference Include="..\..\mailing\Mailing.Service\Mailing.Service.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/

using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums;

Expand All @@ -27,5 +28,5 @@ public interface IOfferSubscriptionService
{
Task<Guid> AddOfferSubscriptionAsync(Guid offerId,
IEnumerable<OfferAgreementConsentData> offerAgreementConsentData, (Guid UserId, Guid CompanyId) identity,
OfferTypeId offerTypeId, string basePortalAddress);
OfferTypeId offerTypeId, string basePortalAddress, IEnumerable<UserRoleConfig> notificationRecipients);
}
59 changes: 22 additions & 37 deletions src/marketplace/Offers.Library/Service/OfferService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models;
using Org.Eclipse.TractusX.Portal.Backend.Framework.Models.Configuration;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.SendMail;
using Org.Eclipse.TractusX.Portal.Backend.Mailing.Service;
using Org.Eclipse.TractusX.Portal.Backend.Notifications.Library;
using Org.Eclipse.TractusX.Portal.Backend.Offers.Library.Models;
using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess;
Expand All @@ -40,7 +40,7 @@ public class OfferService : IOfferService
{
private readonly IPortalRepositories _portalRepositories;
private readonly INotificationService _notificationService;
private readonly IMailingService _mailingService;
private readonly IRoleBaseMailService _roleBaseMailService;
private readonly IOfferSetupService _offerSetupService;

/// <summary>
Expand All @@ -52,12 +52,12 @@ public class OfferService : IOfferService
/// <param name="offerSetupService">The offer Setup Service</param>
public OfferService(IPortalRepositories portalRepositories,
INotificationService notificationService,
IMailingService mailingService,
IRoleBaseMailService roleBaseMailService,
IOfferSetupService offerSetupService)
{
_portalRepositories = portalRepositories;
_notificationService = notificationService;
_mailingService = mailingService;
_roleBaseMailService = roleBaseMailService;
_offerSetupService = offerSetupService;
}

Expand Down Expand Up @@ -559,45 +559,30 @@ public async Task DeclineOfferAsync(Guid offerId, Guid userId, OfferDeclineReque
DeclineMessage = data.Message
};

var serializeNotificationContent = JsonSerializer.Serialize(notificationContent);
var content = Enumerable.Repeat(notificationTypeId, 1).Select(typeId => new ValueTuple<string?, NotificationTypeId>(serializeNotificationContent, typeId));
var content = new (string?, NotificationTypeId)[]
{
(JsonSerializer.Serialize(notificationContent), notificationTypeId)
};

await _notificationService.CreateNotifications(notificationRecipients, userId, content, declineData.CompanyId.Value).AwaitAll().ConfigureAwait(false);
await _notificationService.SetNotificationsForOfferToDone(catenaAdminRoles, submitOfferNotificationTypeIds, offerId).ConfigureAwait(false);

await _portalRepositories.SaveAsync().ConfigureAwait(false);

await SendMail(notificationRecipients, declineData.OfferName, basePortalAddress, data.Message, declineData.CompanyId.Value);
}

private async Task SendMail(IEnumerable<UserRoleConfig> receiverRoles, string offerName, string basePortalAddress, string message, Guid companyId)
{
var receiverUserRoles = receiverRoles;
var userRolesRepository = _portalRepositories.GetInstance<IUserRolesRepository>();
var roleData = await userRolesRepository
.GetUserRoleIdsUntrackedAsync(receiverUserRoles)
.ToListAsync()
.ConfigureAwait(false);
if (roleData.Count < receiverUserRoles.Sum(clientRoles => clientRoles.UserRoleNames.Count()))
{
throw new ConfigurationException(
$"invalid configuration, at least one of the configured roles does not exist in the database: {string.Join(", ", receiverUserRoles.Select(clientRoles => $"client: {clientRoles.ClientId}, roles: [{string.Join(", ", clientRoles.UserRoleNames)}]"))}");
}

var companyUserWithRoleIdForCompany = _portalRepositories.GetInstance<IUserRepository>()
.GetCompanyUserEmailForCompanyAndRoleId(roleData, companyId);
await foreach (var (receiver, firstName, lastName) in companyUserWithRoleIdForCompany)
{
var userName = string.Join(" ", new[] { firstName, lastName }.Where(item => !string.IsNullOrWhiteSpace(item)));

var mailParams = new Dictionary<string, string>
await _roleBaseMailService.RoleBaseSendMail(
notificationRecipients,
new[]
{
{ "offerName", offerName },
{ "url", basePortalAddress },
{ "declineMessage", message },
{ "offerProviderName", !string.IsNullOrWhiteSpace(userName) ? userName : "Service Manager"},
};
await _mailingService.SendMails(receiver, mailParams, new List<string> { "offer-request-decline" }).ConfigureAwait(false);
}
("offerName", declineData.OfferName),
("url", basePortalAddress),
("declineMessage", data.Message),
},
("offerProviderName", "Service Manager"),
new[]
{
"offer-request-decline"
},
declineData.CompanyId.Value).ConfigureAwait(false);
}

private async Task CheckLanguageCodesExist(IEnumerable<string> languageCodes)
Expand Down
Loading

0 comments on commit 5ae0519

Please sign in to comment.