Skip to content

Commit

Permalink
Notification service added to the Saga
Browse files Browse the repository at this point in the history
  • Loading branch information
ebubekirdinc committed Mar 5, 2023
1 parent 6de6f87 commit 6132c13
Show file tree
Hide file tree
Showing 50 changed files with 308 additions and 250 deletions.
5 changes: 4 additions & 1 deletion src/Services/Identity/Identity.API/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static class Config
new ApiResource("resource_assessment",new [] { JwtClaimTypes.Role }) { Scopes = { "assessmentfull_scope" } },
new ApiResource("resource_account",new [] { JwtClaimTypes.Role }) { Scopes = { "accountfull_scope" } },
new ApiResource("resource_order",new [] { JwtClaimTypes.Role }) { Scopes = { "orderfull_scope" } },
new ApiResource("resource_notification",new [] { JwtClaimTypes.Role }) { Scopes = { "notification_scope" } },
new ApiResource(IdentityServerConstants.LocalApi.ScopeName)
};

Expand All @@ -36,6 +37,7 @@ public static class Config
new ApiScope("assessmentfull_scope", "Full permission for assessment"),
new ApiScope("accountfull_scope", "Full permission for account"),
new ApiScope("orderfull_scope", "Full permission for order"),
new ApiScope("notification_scope", "Full permission for notification"),
new ApiScope(IdentityServerConstants.LocalApi.ScopeName),
};

Expand All @@ -49,7 +51,7 @@ public static class Config
ClientId = "WebMvcClient",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ClientCredentials,
AllowedScopes = { "assessmentfull_scope", "accountfull_scope", "orderfull_scope", IdentityServerConstants.LocalApi.ScopeName },
AllowedScopes = { "assessmentfull_scope", "accountfull_scope", "orderfull_scope", "notification_scope", IdentityServerConstants.LocalApi.ScopeName },
},
new Client
{
Expand All @@ -68,6 +70,7 @@ public static class Config
"assessmentfull_scope",
"accountfull_scope",
"orderfull_scope",
"notification_scope",
IdentityServerConstants.StandardScopes.OfflineAccess, // refresh token
},
AccessTokenLifetime = 1 * 60 * 60,
Expand Down
43 changes: 35 additions & 8 deletions src/Services/Notification/src/Infrastructure/ConfigureServices.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using Notification.Application.Common.Interfaces;
using Notification.Infrastructure.Identity;
using Notification.Infrastructure.Persistence;
using Notification.Infrastructure.Persistence.Interceptors;
using Notification.Infrastructure.Services;
using MassTransit;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Notification.Application.Common.Interfaces;
using Notification.Infrastructure.Consumers;
using Notification.Infrastructure.Persistence;
using Notification.Infrastructure.Persistence.Interceptors;
using Notification.Infrastructure.Services;
using Shared.Constants;

namespace Microsoft.Extensions.DependencyInjection;
namespace Notification.Infrastructure;

public static class ConfigureServices
{
Expand Down Expand Up @@ -41,6 +43,31 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti
services.AddAuthorization(options =>
options.AddPolicy("CanPurge", policy => policy.RequireRole("Administrator")));

services.AddMassTransit(x =>
{
x.AddConsumer<OrderCompletedEventConsumer>();
x.AddConsumer<OrderFailedEventConsumer>();

x.UsingRabbitMq((context, cfg) =>
{
cfg.Host(configuration["RabbitMQUrl"], "/", host =>
{
host.Username("user");
host.Password("password");
});

cfg.ReceiveEndpoint(QueuesConsts.OrderRequestCompletedEventtQueueName, x =>
{
x.ConfigureConsumer<OrderCompletedEventConsumer>(context);
});

cfg.ReceiveEndpoint(QueuesConsts.OrderRequestFailedEventtQueueName, x =>
{
x.ConfigureConsumer<OrderFailedEventConsumer>(context);
});
});
});

return services;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Shared.Events.Interfaces;

namespace Notification.Infrastructure.Consumers;

public class OrderCompletedEventConsumer : IConsumer<IOrderCompletedEvent>
{
private readonly ILogger<OrderCompletedEventConsumer> _logger;

public OrderCompletedEventConsumer(ILogger<OrderCompletedEventConsumer> logger)
{
_logger = logger;
}

public async Task Consume(ConsumeContext<IOrderCompletedEvent> context)
{
// TODO: Send email to customer

_logger.LogInformation($"Order (Id={context.Message.OrderId}) Order Completed notification sent");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Shared.Events.Interfaces;

namespace Notification.Infrastructure.Consumers;

public class OrderFailedEventConsumer : IConsumer<IOrderFailedEvent>
{
private readonly ILogger<OrderFailedEventConsumer> _logger;

public OrderFailedEventConsumer(ILogger<OrderFailedEventConsumer> logger)
{
_logger = logger;
}

public async Task Consume(ConsumeContext<IOrderFailedEvent> context)
{
// TODO: Send email to customer

_logger.LogInformation($"Order (Id={context.Message.OrderId}) Order Completed notification sent");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

<ItemGroup>
<PackageReference Include="CsvHelper" Version="15.0.10" />
<PackageReference Include="MassTransit.AspNetCore" Version="7.3.1" />
<PackageReference Include="MassTransit.RabbitMQ" Version="8.0.12" />
<PackageReference Include="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="7.0.0-rc.2.22476.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.0-rc.2.22476.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0-rc.2.22476.2" />
Expand All @@ -19,6 +21,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\Shared\Shared.csproj" />
<ProjectReference Include="..\Application\Application.csproj" />
</ItemGroup>

Expand Down
1 change: 1 addition & 0 deletions src/Services/Notification/src/WebUI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Notification.Infrastructure;
using Notification.Infrastructure.Persistence;
using WebUI.Middlewares;

Expand Down
1 change: 1 addition & 0 deletions src/Services/Notification/src/WebUI/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"UseInMemoryDatabase": false,
"RabbitMQUrl": "localhost",
"ConnectionStrings": {
"DefaultConnection": "User ID=admin; Password=admin1234; Server=localhost; Port=5433;Database=AssessmentDb;Integrated Security=true;Pooling=true"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
using Shared.Constants;
using Shared.Dto;
using Shared.Events;
using Shared.Interfaces;
using Shared.Events.Interfaces;
using Shared.Messages;
using Shared.Messages.Interfaces;
using OrderItem = Shared.Events.OrderItem;

namespace Order.Application.Order.Commands.CreateOrder;

Expand Down Expand Up @@ -36,14 +39,14 @@ public async Task<ApiResult<string>> Handle(CreateOrderCommand request, Cancella

request.OrderItems.ForEach(item =>
{
newOrder.OrderItems.Add(new OrderItem { Price = item.Price, ProductId = item.ProductId, Count = item.Count, });
newOrder.OrderItems.Add(new Domain.Entities.OrderItem { Price = item.Price, ProductId = item.ProductId, Count = item.Count, });
});

await _context.Orders.AddAsync(newOrder, cancellationToken);

await _context.SaveChangesAsync(cancellationToken);

var orderCreatedRequestEvent = new OrderCreatedRequestEvent()
var createOrderMessage = new CreateOrderMessage()
{
CustomerId = request.CustomerId,
OrderId = newOrder.Id,
Expand All @@ -53,10 +56,10 @@ public async Task<ApiResult<string>> Handle(CreateOrderCommand request, Cancella

newOrder.OrderItems.ForEach(item =>
{
orderCreatedRequestEvent.OrderItems.Add(new OrderCreatedRequestEventItem { Count = item.Count, ProductId = item.ProductId });
createOrderMessage.OrderItems.Add(new OrderItem { Count = item.Count, ProductId = item.ProductId });
});

await _massTransitService.Send<IOrderCreatedRequestEvent>(orderCreatedRequestEvent, QueuesConsts.OrderCreatedRequest);
await _massTransitService.Send<ICreateOrderMessage>(createOrderMessage, QueuesConsts.CreateOrderMessageQueueName);


return new ApiResult<string>(true, "Order created successfully");
Expand Down
8 changes: 4 additions & 4 deletions src/Services/Order/src/Infrastructure/ConfigureServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti

services.AddMassTransit(x =>
{
x.AddConsumer<OrderRequestCompletedEventConsumer>();
x.AddConsumer<OrderRequestFailedEventConsumer>();
x.AddConsumer<OrderCompletedEventConsumer>();
x.AddConsumer<OrderFailedEventConsumer>();

x.UsingRabbitMq((context, cfg) =>
{
Expand All @@ -60,12 +60,12 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti

cfg.ReceiveEndpoint(QueuesConsts.OrderRequestCompletedEventtQueueName, x =>
{
x.ConfigureConsumer<OrderRequestCompletedEventConsumer>(context);
x.ConfigureConsumer<OrderCompletedEventConsumer>(context);
});

cfg.ReceiveEndpoint(QueuesConsts.OrderRequestFailedEventtQueueName, x =>
{
x.ConfigureConsumer<OrderRequestFailedEventConsumer>(context);
x.ConfigureConsumer<OrderFailedEventConsumer>(context);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
using Microsoft.Extensions.Logging;
using Order.Domain.Enums;
using Order.Infrastructure.Persistence;
using Shared.Interfaces;
using Shared.Events.Interfaces;

namespace Order.Infrastructure.Consumers;

public class OrderRequestCompletedEventConsumer : IConsumer<IOrderRequestCompletedEvent>
public class OrderCompletedEventConsumer : IConsumer<IOrderCompletedEvent>
{
private readonly ApplicationDbContext _context;

private readonly ILogger<OrderRequestCompletedEventConsumer> _logger;
private readonly ILogger<OrderCompletedEventConsumer> _logger;

public OrderRequestCompletedEventConsumer(ApplicationDbContext context, ILogger<OrderRequestCompletedEventConsumer> logger)
public OrderCompletedEventConsumer(ApplicationDbContext context, ILogger<OrderCompletedEventConsumer> logger)
{
_context = context;
_logger = logger;
}

public async Task Consume(ConsumeContext<IOrderRequestCompletedEvent> context)
public async Task Consume(ConsumeContext<IOrderCompletedEvent> context)
{
var order = await _context.Orders.FindAsync(context.Message.OrderId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@
using Microsoft.Extensions.Logging;
using Order.Domain.Enums;
using Order.Infrastructure.Persistence;
using Shared.Interfaces;
using Shared.Events.Interfaces;

namespace Order.Infrastructure.Consumers;

public class OrderRequestFailedEventConsumer : IConsumer<IOrderRequestFailedEvent>
public class OrderFailedEventConsumer : IConsumer<IOrderFailedEvent>
{
private readonly ApplicationDbContext _context;

private readonly ILogger<OrderRequestFailedEventConsumer> _logger;
private readonly ILogger<OrderFailedEventConsumer> _logger;

public OrderRequestFailedEventConsumer(ApplicationDbContext context, ILogger<OrderRequestFailedEventConsumer> logger)
public OrderFailedEventConsumer(ApplicationDbContext context, ILogger<OrderFailedEventConsumer> logger)
{
_context = context;
_logger = logger;
}

public async Task Consume(ConsumeContext<IOrderRequestFailedEvent> context)
public async Task Consume(ConsumeContext<IOrderFailedEvent> context)
{
var order = await _context.Orders.FindAsync(context.Message.OrderId);

Expand Down
6 changes: 3 additions & 3 deletions src/Services/Payment/src/Infrastructure/ConfigureServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti

services.AddMassTransit(x =>
{
x.AddConsumer<StockReservedRequestPaymentConsumer>();
x.AddConsumer<CompletePaymentMessageConsumer>();

x.UsingRabbitMq((context, cfg) =>
{
Expand All @@ -56,9 +56,9 @@ public static IServiceCollection AddInfrastructureServices(this IServiceCollecti
host.Password("password");
});

cfg.ReceiveEndpoint(QueuesConsts.PaymentStockReservedRequestQueueName, e =>
cfg.ReceiveEndpoint(QueuesConsts.CompletePaymentMessageQueueName, e =>
{
e.ConfigureConsumer<StockReservedRequestPaymentConsumer>(context);
e.ConfigureConsumer<CompletePaymentMessageConsumer>(context);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using MassTransit;
using Microsoft.Extensions.Logging;
using Shared.Events;
using Shared.Messages.Interfaces;

namespace Payment.Infrastructure.Consumers;

public class CompletePaymentMessageConsumer : IConsumer<ICompletePaymentMessage>
{
private readonly ILogger<CompletePaymentMessageConsumer> _logger;

private readonly IPublishEndpoint _publishEndpoint;

public CompletePaymentMessageConsumer(ILogger<CompletePaymentMessageConsumer> logger, IPublishEndpoint publishEndpoint)
{
_logger = logger;
_publishEndpoint = publishEndpoint;
}

public async Task Consume(ConsumeContext<ICompletePaymentMessage> context)
{
var balance = 3000m;

if (balance > context.Message.TotalPrice)
{
_logger.LogInformation($"{context.Message.TotalPrice} was withdrawn from credit card for user id= {context.Message.CustomerId}");

await _publishEndpoint.Publish(new PaymentCompletedEvent(context.Message.CorrelationId));
}
else
{
_logger.LogInformation($"{context.Message.TotalPrice} was not withdrawn from credit card for user id={context.Message.CustomerId}");

await _publishEndpoint.Publish(new PaymentFailedEvent(context.Message.CorrelationId) { Reason = "not enough balance", OrderItems = context.Message.OrderItems });
}
}
}

This file was deleted.

Loading

0 comments on commit 6132c13

Please sign in to comment.