From 28cd2346963f996eecbc58d6d226efc68a43e1f9 Mon Sep 17 00:00:00 2001 From: Akber Date: Thu, 1 Feb 2024 17:03:11 +0400 Subject: [PATCH 1/7] Add retry policy in auto migrate in common project. --- .../App/Extensions/ApplictionBuilderExtension.cs | 10 +++++++--- crs/Services/Email/Email.App/Email.App.csproj | 4 ++++ .../Configurations/EventBusServiceInstaller.cs | 7 +++++-- crs/Services/Identity/Identity.App/GlobalUsings.cs | 4 +++- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crs/CommonComponents/Common/App/Extensions/ApplictionBuilderExtension.cs b/crs/CommonComponents/Common/App/Extensions/ApplictionBuilderExtension.cs index ed267ed..9ccedba 100644 --- a/crs/CommonComponents/Common/App/Extensions/ApplictionBuilderExtension.cs +++ b/crs/CommonComponents/Common/App/Extensions/ApplictionBuilderExtension.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.EntityFrameworkCore; +using Polly; namespace Common.App.Extensions; @@ -19,10 +20,13 @@ public static IApplicationBuilder MigrateDbContext(this IApplication { using var scope = builder.ApplicationServices.CreateScope(); using var dbContext = scope.ServiceProvider.GetRequiredService(); - - - dbContext.Database.Migrate(); + Policy + .Handle() + .WaitAndRetry( + retryCount: 3, + _ => TimeSpan.FromSeconds(15)) + .Execute(dbContext.Database.Migrate); return builder; } diff --git a/crs/Services/Email/Email.App/Email.App.csproj b/crs/Services/Email/Email.App/Email.App.csproj index 1203962..f5d489e 100644 --- a/crs/Services/Email/Email.App/Email.App.csproj +++ b/crs/Services/Email/Email.App/Email.App.csproj @@ -25,4 +25,8 @@ + + + + diff --git a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs b/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs index ee9b10e..6f16103 100644 --- a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs +++ b/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs @@ -6,11 +6,11 @@ public void Install(IServiceCollection services, IConfiguration configuration) { services.AddMassTransit(configure => { - configure.AddConsumers(App.AssemblyReference.Assembly); + configure.SetKebabCaseEndpointNameFormatter(); configure.UsingRabbitMq((context, configurator) => { - configurator.Host("rabbitmq", "/", hostConfigurator => + configurator.Host("rabbitmq", "/", hostConfigurator => { hostConfigurator.Username(Env.RABBITMQ_DEFAULT_USER); hostConfigurator.Password(Env.RABBITMQ_DEFAULT_PASS); @@ -18,7 +18,10 @@ public void Install(IServiceCollection services, IConfiguration configuration) configurator.ConfigureEndpoints(context); }); + + configure.AddConsumers(App.AssemblyReference.Assembly); }); + services.AddTransient(); } } diff --git a/crs/Services/Identity/Identity.App/GlobalUsings.cs b/crs/Services/Identity/Identity.App/GlobalUsings.cs index 0a02186..892b07e 100644 --- a/crs/Services/Identity/Identity.App/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.App/GlobalUsings.cs @@ -26,4 +26,6 @@ global using OpenTelemetry.Metrics; global using Prometheus; global using Common.App.HealthChecks; -global using MassTransit; \ No newline at end of file +global using MassTransit; +global using EventBus.Common.Abstractions; +global using EventBus.MassTransit.RabbitMQ.Services; From c62a73ace0b3f57636166985da08ca1c7081ca61 Mon Sep 17 00:00:00 2001 From: Akber Date: Fri, 2 Feb 2024 20:20:27 +0400 Subject: [PATCH 2/7] Add more logic from ServiceBus --- .../Common/Domain/Primitives/Enumeration.cs | 31 ++++++---- .../Domain/Primitives/Events/IDomainEvent.cs | 2 +- crs/CommonComponents/Common/Events/IEvent.cs | 5 -- crs/CommonComponents/Common/GlobalUsings.cs | 1 - .../Contracts/Abstractions/Abstractions.proto | 16 ++++++ .../Attributes/RoleBasedAuthorizeFilter.cs | 20 +++++++ .../Contracts/Contracts.csproj | 10 ++++ .../Contracts/Enumurations/Gender.cs | 8 +++ .../Contracts/Enumurations/Role.cs | 8 +++ .../Contracts/GlobalUsings.cs | 2 + ...UserCreatedConfirmationEmailSentCommand.cs | 6 ++ .../Services/Identity/Identity.proto | 23 ++++++++ .../EventBus.Common/Abstractions/IEventBus.cs | 16 ------ .../Abstractions/IIntegrationCommand.cs | 8 +++ .../Abstractions/IIntegrationEvent.cs | 15 +---- .../Abstractions/IIntegrationEventHandler.cs | 7 --- .../EventBus.Common/Abstractions/IMessage.cs | 17 ++++++ .../Abstractions/IMessageBus.cs | 25 ++++++++ ...entBusBuilder.cs => IMessageBusBuilder.cs} | 2 +- .../EventBus/EventBus.Common/GlobalUsings.cs | 1 - .../Messages/IntegrationCommand.cs | 13 +++++ .../{Events => Messages}/IntegrationEvent.cs | 10 +--- .../Services/EventBusRabitMQ.cs | 11 +++- .../Abstractions/IMessageHandler.cs | 7 +++ .../EventBus/EventBus.MassTransit/Consumer.cs | 7 --- .../EventBus.MassTransit/GlobalUsings.cs | 3 +- .../Handlers/IntegrationCommandHandler.cs | 7 +++ .../Handlers/IntegrationEventHandler.cs | 7 +++ .../Handlers/MessageHandler.cs | 13 +++++ .../Catalog.Presentation.csproj | 1 + .../Catalog.Presentation/GlobalUsings.cs | 1 + .../V1/Controllers/BrandsController.cs | 12 ++-- crs/Services/Email/Email.App/Program.cs | 2 +- .../EventBusServiceInstaller.cs | 2 +- .../Identity.Application/GlobalUsings.cs | 4 +- .../Identity.Application.csproj | 1 + .../Commands/Register/RegisterCommand.cs | 2 +- .../Register/RegisterCommandHandler.cs | 25 +++++--- .../Register/RegisterCommandValidator.cs | 16 +++--- .../RetryConfirmEmailSendCommand.cs | 1 - .../RetryConfirmEmailSendCommandHandler.cs | 12 ++-- .../Queries/GetRoles/GetRolesQueryHandler.cs | 2 +- .../Queries/GetRoles/GetRolesQueryResponse.cs | 2 +- .../Identity/Identity.Domain/GlobalUsings.cs | 2 +- .../Identity.Domain/Identity.Domain.csproj | 1 + .../UserAggregate/Enums/Role.cs | 7 --- .../Identity.Domain/UserAggregate/User.cs | 11 +++- .../Authentication/JwtProvider.cs | 2 +- .../Configurations/UserConfiguration.cs | 2 + .../Identity.Presentation.csproj | 6 -- .../V1/Controllers/UserController.cs | 5 +- .../V1/Models/ConfirmEmailRequest.cs | 3 +- .../V1/Models/RegisterRequest.cs | 1 + .../V1/Templates/ConfirmEmailTemplate.html | 57 ------------------- 54 files changed, 295 insertions(+), 186 deletions(-) delete mode 100644 crs/CommonComponents/Common/Events/IEvent.cs create mode 100644 crs/CommonComponents/Contracts/Abstractions/Abstractions.proto create mode 100644 crs/CommonComponents/Contracts/Attributes/RoleBasedAuthorizeFilter.cs create mode 100644 crs/CommonComponents/Contracts/Enumurations/Gender.cs create mode 100644 crs/CommonComponents/Contracts/Enumurations/Role.cs create mode 100644 crs/CommonComponents/Contracts/GlobalUsings.cs create mode 100644 crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs create mode 100644 crs/CommonComponents/Contracts/Services/Identity/Identity.proto delete mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBus.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationCommand.cs delete mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEventHandler.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessage.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs rename crs/CommonComponents/EventBus/EventBus.Common/Abstractions/{IEventBusBuilder.cs => IMessageBusBuilder.cs} (71%) create mode 100644 crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationCommand.cs rename crs/CommonComponents/EventBus/EventBus.Common/{Events => Messages}/IntegrationEvent.cs (58%) create mode 100644 crs/CommonComponents/EventBus/EventBus.MassTransit/Abstractions/IMessageHandler.cs delete mode 100644 crs/CommonComponents/EventBus/EventBus.MassTransit/Consumer.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationCommandHandler.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationEventHandler.cs create mode 100644 crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/MessageHandler.cs delete mode 100644 crs/Services/Identity/Identity.Domain/UserAggregate/Enums/Role.cs delete mode 100644 crs/Services/Identity/Identity.Presentation/V1/Templates/ConfirmEmailTemplate.html diff --git a/crs/CommonComponents/Common/Domain/Primitives/Enumeration.cs b/crs/CommonComponents/Common/Domain/Primitives/Enumeration.cs index a72cc3c..458da46 100644 --- a/crs/CommonComponents/Common/Domain/Primitives/Enumeration.cs +++ b/crs/CommonComponents/Common/Domain/Primitives/Enumeration.cs @@ -1,30 +1,36 @@ namespace Common.Domain.Primitives; -public abstract class Enumeration( - int value, - string name) - +public abstract class Enumeration(int value, string name) where TEnum : Enumeration { public readonly int Value = value; public readonly string Name = name; - private static readonly Dictionary _enumerations = GetEnumerations(); + private static readonly Dictionary _enumerations = GetEnumerations(); public static TEnum? FromValue(int value) => - _enumerations.TryGetValue(value, out var enumeration) + _enumerations.TryGetValue(value, out var enumeration) ? enumeration : null; - public static TEnum? FromName(string name) => - _enumerations.Values.SingleOrDefault(x => x.Name == name); + public static TEnum FromName(string name) => + _enumerations.Values.Single(x => x.Name == name); + + public static IEnumerable GetNames() => + _enumerations.Values.Select(x => x.Name); + + public static bool NameExists(string name) => + _enumerations.Values.Any(x => x.Name == name); + + public static bool ValueExists(int value) => + _enumerations.ContainsKey(value); private static Dictionary GetEnumerations() { var enumerationType = typeof(TEnum); var fields = enumerationType.GetFields( - BindingFlags.Public | - BindingFlags.Static | + BindingFlags.Public | + BindingFlags.Static | BindingFlags.DeclaredOnly) .Where(fieldInfo => enumerationType.IsAssignableFrom(fieldInfo.FieldType)) .Select(fieldInfo => (TEnum)fieldInfo.GetValue(default)!); @@ -32,4 +38,9 @@ private static Dictionary GetEnumerations() return fields.ToDictionary(field => field.Value); } + public static implicit operator int(Enumeration @enum) => + @enum.Value; + + public static implicit operator string(Enumeration @enum) => + @enum.Name; } diff --git a/crs/CommonComponents/Common/Domain/Primitives/Events/IDomainEvent.cs b/crs/CommonComponents/Common/Domain/Primitives/Events/IDomainEvent.cs index ea0d793..a415383 100644 --- a/crs/CommonComponents/Common/Domain/Primitives/Events/IDomainEvent.cs +++ b/crs/CommonComponents/Common/Domain/Primitives/Events/IDomainEvent.cs @@ -4,7 +4,7 @@ /// Interface for domain event. /// if you need class. because class can't inherit from record. /// -public interface IDomainEvent : INotification, IEvent +public interface IDomainEvent : INotification { /// /// Gets the id of the event. diff --git a/crs/CommonComponents/Common/Events/IEvent.cs b/crs/CommonComponents/Common/Events/IEvent.cs deleted file mode 100644 index 3503323..0000000 --- a/crs/CommonComponents/Common/Events/IEvent.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Common.Events; - -public interface IEvent -{ -} diff --git a/crs/CommonComponents/Common/GlobalUsings.cs b/crs/CommonComponents/Common/GlobalUsings.cs index b99c2ea..f582729 100644 --- a/crs/CommonComponents/Common/GlobalUsings.cs +++ b/crs/CommonComponents/Common/GlobalUsings.cs @@ -14,4 +14,3 @@ global using FluentValidation; global using Microsoft.AspNetCore.Mvc; global using Microsoft.AspNetCore.Http; -global using Common.Events; diff --git a/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto new file mode 100644 index 0000000..031c73c --- /dev/null +++ b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package Contracts.Abstractions.Protobuf; + +message GetResponse{ + oneof OneOf{ + google.protobuf.Any Projection = 1; + NotFound NotFound = 2; + } +} + +message NotFound {} + +message Result { + +} \ No newline at end of file diff --git a/crs/CommonComponents/Contracts/Attributes/RoleBasedAuthorizeFilter.cs b/crs/CommonComponents/Contracts/Attributes/RoleBasedAuthorizeFilter.cs new file mode 100644 index 0000000..4f436eb --- /dev/null +++ b/crs/CommonComponents/Contracts/Attributes/RoleBasedAuthorizeFilter.cs @@ -0,0 +1,20 @@ +//using Contracts.Enumurations; +//using Microsoft.AspNetCore.Authentication; +//using Microsoft.AspNetCore.Mvc; +//using Microsoft.AspNetCore.Mvc.Filters; + +//namespace Contracts.Attributes; + +//public class RoleBasedAuthorizeFilter(Role role) : IAuthorizationFilter +//{ +// private readonly Role role = role; + +// public void OnAuthorization(AuthorizationFilterContext context) +// { +// if (!context.HttpContext.User.Identity.IsAuthenticated) +// { +// context.Result = new ChallengeResult(); +// return; +// } +// } +//} diff --git a/crs/CommonComponents/Contracts/Contracts.csproj b/crs/CommonComponents/Contracts/Contracts.csproj index fa71b7a..e817cc5 100644 --- a/crs/CommonComponents/Contracts/Contracts.csproj +++ b/crs/CommonComponents/Contracts/Contracts.csproj @@ -6,4 +6,14 @@ enable + + + + + + + + + + diff --git a/crs/CommonComponents/Contracts/Enumurations/Gender.cs b/crs/CommonComponents/Contracts/Enumurations/Gender.cs new file mode 100644 index 0000000..16773d0 --- /dev/null +++ b/crs/CommonComponents/Contracts/Enumurations/Gender.cs @@ -0,0 +1,8 @@ +namespace Contracts.Enumurations; + +public class Gender(int value, string name) : Enumeration(value, name) +{ + public static readonly Gender Male = new(1, nameof(Male)); + public static readonly Gender Female = new(2, nameof(Female)); + public static readonly Gender Undefined = new(3, nameof(Undefined)); +} diff --git a/crs/CommonComponents/Contracts/Enumurations/Role.cs b/crs/CommonComponents/Contracts/Enumurations/Role.cs new file mode 100644 index 0000000..63c58c8 --- /dev/null +++ b/crs/CommonComponents/Contracts/Enumurations/Role.cs @@ -0,0 +1,8 @@ +namespace Contracts.Enumurations; + +public class Role(int value, string name) + : Enumeration(value, name) +{ + public static readonly Role User = new(1, nameof(User)); + public static readonly Role Admin = new(2, nameof(Admin)); +} diff --git a/crs/CommonComponents/Contracts/GlobalUsings.cs b/crs/CommonComponents/Contracts/GlobalUsings.cs new file mode 100644 index 0000000..598954c --- /dev/null +++ b/crs/CommonComponents/Contracts/GlobalUsings.cs @@ -0,0 +1,2 @@ +global using Common.Domain.Primitives; +global using EventBus.Common.Messages; diff --git a/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs b/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs new file mode 100644 index 0000000..decbaa8 --- /dev/null +++ b/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs @@ -0,0 +1,6 @@ +namespace Contracts.Services.Identity.Commands; + +public sealed record UserCreatedConfirmationEmailSendCommand( + Guid Id, + Guid UserId, + string returnUrl) : IntegrationCommand(Id); diff --git a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto new file mode 100644 index 0000000..0dece2f --- /dev/null +++ b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package Contracts.Services.Idenitty.Protobuf; + +import "Abstractions/Abstractions.proto"; + +service IdenittyService { + rpc GetUser(GetUserRequest) returns (Abstractions.Protobuf.GetResponse); +} + +message GetUserRequest { + string Id = 1; +} + +message GetUserResponse { + oneof OneOf{ + User + } +} + +message User { + string +} \ No newline at end of file diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBus.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBus.cs deleted file mode 100644 index 7d34c68..0000000 --- a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBus.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace EventBus.Common.Abstractions; - -/// -/// Base interfase for event bus. -/// -public interface IEventBus -{ - /// - /// Publish event. - /// - /// The event. - /// The cancellation token. - /// The . - Task Publish(TEvent @event, CancellationToken cancellationToken = default) - where TEvent : IEvent; -} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationCommand.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationCommand.cs new file mode 100644 index 0000000..8540475 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationCommand.cs @@ -0,0 +1,8 @@ +namespace EventBus.Common.Abstractions; + +/// +/// The integration command interface. +/// +public interface IIntegrationCommand : IMessage +{ +} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEvent.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEvent.cs index 3f6fdc3..0354523 100644 --- a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEvent.cs +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEvent.cs @@ -1,17 +1,8 @@ namespace EventBus.Common.Abstractions; /// -/// Inteface for integration event. +/// The integration command interface. /// -public interface IIntegrationEvent: IEvent +public interface IIntegrationEvent : IMessage { - /// - /// The id event. - /// - Guid Id { get; } - - /// - /// The creation date of the event. - /// - DateTime CreatedAt { get; } -} \ No newline at end of file +} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEventHandler.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEventHandler.cs deleted file mode 100644 index 8466f40..0000000 --- a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IIntegrationEventHandler.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EventBus.Common.Abstractions; - -public interface IIntegrationEventHandler - where TIntegrationEvent : IIntegrationEvent -{ - Task Handle(TIntegrationEvent @event); -} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessage.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessage.cs new file mode 100644 index 0000000..42a6ef3 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessage.cs @@ -0,0 +1,17 @@ +namespace EventBus.Common.Abstractions; + +/// +/// The message interface. +/// +public interface IMessage +{ + /// + /// The id message. + /// + Guid Id { get; } + + /// + /// The creation date of the message. + /// + DateTime CreatedAt { get; } +} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs new file mode 100644 index 0000000..c0886b7 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs @@ -0,0 +1,25 @@ +namespace EventBus.Common.Abstractions; + +/// +/// Base interfase for event bus. +/// +public interface IMessageBus +{ + /// + /// Publish event. + /// + /// The event. + /// The cancellation token. + /// The . + Task Publish(TEvent @event, CancellationToken cancellationToken = default) + where TEvent : IIntegrationEvent; + + /// + /// Send command. + /// + /// The command. + /// The cancellation token. + /// The . + Task Send(TCommand command, CancellationToken cancellationToken = default) + where TCommand : IIntegrationCommand; +} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBusBuilder.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBusBuilder.cs similarity index 71% rename from crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBusBuilder.cs rename to crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBusBuilder.cs index ec409a0..347fa86 100644 --- a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IEventBusBuilder.cs +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBusBuilder.cs @@ -1,6 +1,6 @@ namespace EventBus.Common.Abstractions; -public interface IEventBusBuilder +public interface IMessageBusBuilder { IServiceCollection Services { get; } } diff --git a/crs/CommonComponents/EventBus/EventBus.Common/GlobalUsings.cs b/crs/CommonComponents/EventBus/EventBus.Common/GlobalUsings.cs index 3752994..5a5a01e 100644 --- a/crs/CommonComponents/EventBus/EventBus.Common/GlobalUsings.cs +++ b/crs/CommonComponents/EventBus/EventBus.Common/GlobalUsings.cs @@ -1,3 +1,2 @@ global using Microsoft.Extensions.DependencyInjection; global using EventBus.Common.Abstractions; -global using Common.Events; diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationCommand.cs b/crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationCommand.cs new file mode 100644 index 0000000..91e9d92 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationCommand.cs @@ -0,0 +1,13 @@ +namespace EventBus.Common.Messages; + +/// +/// The command. +/// +/// The identifier command. +public abstract record IntegrationCommand(Guid Id) : IIntegrationCommand +{ + /// + /// The creation date of the command. + /// + public DateTime CreatedAt { get; private set; } = DateTime.UtcNow; +} diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Events/IntegrationEvent.cs b/crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationEvent.cs similarity index 58% rename from crs/CommonComponents/EventBus/EventBus.Common/Events/IntegrationEvent.cs rename to crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationEvent.cs index 524bde0..3192d9f 100644 --- a/crs/CommonComponents/EventBus/EventBus.Common/Events/IntegrationEvent.cs +++ b/crs/CommonComponents/EventBus/EventBus.Common/Messages/IntegrationEvent.cs @@ -1,15 +1,11 @@ -namespace EventBus.Common.Events; +namespace EventBus.Common.Messages; /// -/// class for integration event. +/// The integration event. /// +/// The identifier event. public abstract record IntegrationEvent(Guid Id) : IIntegrationEvent { - /// - /// The id event. - /// - public Guid Id { get; private set; } = Id; - /// /// The creation date of the event. /// diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/Services/EventBusRabitMQ.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/Services/EventBusRabitMQ.cs index 16040fc..3f4b0c9 100644 --- a/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/Services/EventBusRabitMQ.cs +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/Services/EventBusRabitMQ.cs @@ -1,13 +1,20 @@ namespace EventBus.MassTransit.RabbitMQ.Services; -public sealed class EventBusRabitMQ(IBusControl busControl) : IEventBus +public sealed class EventBusRabitMQ(IBusControl busControl) : IMessageBus { private readonly IBusControl _busControl = busControl; public async Task Publish (TEvent @event, CancellationToken cancellationToken = default) - where TEvent : IEvent + where TEvent : IIntegrationEvent { await _busControl.Publish(@event, cancellationToken); } + + public async Task Send + (TCommand command, CancellationToken cancellationToken = default) + where TCommand : IIntegrationCommand + { + await _busControl.Send(command, cancellationToken); + } } diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/Abstractions/IMessageHandler.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/Abstractions/IMessageHandler.cs new file mode 100644 index 0000000..0ac033d --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit/Abstractions/IMessageHandler.cs @@ -0,0 +1,7 @@ +namespace EventBus.MassTransit.Abstractions; + +public interface IMessageHandler + where TMessage : class, IMessage +{ + Task Handle(ConsumeContext context); +} diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/Consumer.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/Consumer.cs deleted file mode 100644 index 94f1851..0000000 --- a/crs/CommonComponents/EventBus/EventBus.MassTransit/Consumer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EventBus.MassTransit; - -public abstract class Consumer : IConsumer - where TEvent : class, IEvent -{ - public abstract Task Consume(ConsumeContext context); -} diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/GlobalUsings.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/GlobalUsings.cs index 135abbb..521ac50 100644 --- a/crs/CommonComponents/EventBus/EventBus.MassTransit/GlobalUsings.cs +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit/GlobalUsings.cs @@ -1,2 +1,3 @@ global using MassTransit; -global using Common.Events; +global using EventBus.Common.Abstractions; +global using EventBus.MassTransit.Abstractions; diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationCommandHandler.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationCommandHandler.cs new file mode 100644 index 0000000..804f4a7 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationCommandHandler.cs @@ -0,0 +1,7 @@ +namespace EventBus.MassTransit.Handlers; + +public abstract class IntegrationCommandHandler : + MessageHandler + where TIntegrationCommand : class, IIntegrationCommand +{ +} diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationEventHandler.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationEventHandler.cs new file mode 100644 index 0000000..f531fc4 --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/IntegrationEventHandler.cs @@ -0,0 +1,7 @@ +namespace EventBus.MassTransit.Handlers; + +public abstract class IntegrationEventHandler : + MessageHandler + where TIntegrationEvent : class, IIntegrationEvent +{ +} diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/MessageHandler.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/MessageHandler.cs new file mode 100644 index 0000000..739bc5d --- /dev/null +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit/Handlers/MessageHandler.cs @@ -0,0 +1,13 @@ +namespace EventBus.MassTransit.Handlers; + +public abstract class MessageHandler : + IConsumer, IMessageHandler + where TMessage : class, IMessage +{ + public async Task Consume(ConsumeContext context) + { + await Handle(context); + } + + public abstract Task Handle(ConsumeContext context); +} diff --git a/crs/Services/Catalog/Catalog.Presentation/Catalog.Presentation.csproj b/crs/Services/Catalog/Catalog.Presentation/Catalog.Presentation.csproj index 8f4196d..3dd65d8 100644 --- a/crs/Services/Catalog/Catalog.Presentation/Catalog.Presentation.csproj +++ b/crs/Services/Catalog/Catalog.Presentation/Catalog.Presentation.csproj @@ -12,6 +12,7 @@ + diff --git a/crs/Services/Catalog/Catalog.Presentation/GlobalUsings.cs b/crs/Services/Catalog/Catalog.Presentation/GlobalUsings.cs index 74310f8..1a3d597 100644 --- a/crs/Services/Catalog/Catalog.Presentation/GlobalUsings.cs +++ b/crs/Services/Catalog/Catalog.Presentation/GlobalUsings.cs @@ -5,3 +5,4 @@ global using System.ComponentModel.DataAnnotations; global using System.Reflection; global using Microsoft.AspNetCore.Authorization; +global using Contracts.Enumurations; diff --git a/crs/Services/Catalog/Catalog.Presentation/V1/Controllers/BrandsController.cs b/crs/Services/Catalog/Catalog.Presentation/V1/Controllers/BrandsController.cs index 6378c69..164eb34 100644 --- a/crs/Services/Catalog/Catalog.Presentation/V1/Controllers/BrandsController.cs +++ b/crs/Services/Catalog/Catalog.Presentation/V1/Controllers/BrandsController.cs @@ -20,10 +20,10 @@ public async Task CreateBrand( : HandleFailure(result); } - //[HttpGet] - //[Authorize(Roles = "User")] - //public async Task Test() - //{ - // return Ok("hi"); - //} + [HttpGet] + [Authorize(Roles = "Admin")] + public async Task Test() + { + return Ok("hi"); + } } diff --git a/crs/Services/Email/Email.App/Program.cs b/crs/Services/Email/Email.App/Program.cs index 0927e47..1897763 100644 --- a/crs/Services/Email/Email.App/Program.cs +++ b/crs/Services/Email/Email.App/Program.cs @@ -11,4 +11,4 @@ static IHostBuilder CreateHostBuilder(string[] args) => }); webBuilder.UseStartup(); - }); + }); \ No newline at end of file diff --git a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs b/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs index 6f16103..2f1f39c 100644 --- a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs +++ b/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs @@ -22,6 +22,6 @@ public void Install(IServiceCollection services, IConfiguration configuration) configure.AddConsumers(App.AssemblyReference.Assembly); }); - services.AddTransient(); + services.AddTransient(); } } diff --git a/crs/Services/Identity/Identity.Application/GlobalUsings.cs b/crs/Services/Identity/Identity.Application/GlobalUsings.cs index c11830b..70d491c 100644 --- a/crs/Services/Identity/Identity.Application/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.Application/GlobalUsings.cs @@ -2,7 +2,6 @@ global using Identity.Application.Abstractions; global using Identity.Domain.UserAggregate; global using Identity.Domain.UserAggregate.DomainEvents; -global using Identity.Domain.UserAggregate.Enums; global using Identity.Domain.UserAggregate.Errors; global using Identity.Domain.UserAggregate.Repositories; global using Identity.Domain.UserAggregate.ValueObjects; @@ -13,6 +12,7 @@ global using Common.Domain.Primitives.Events; global using Common.Domain.Primitives.Results; global using FluentValidation; -global using System.IdentityModel.Tokens.Jwt; global using System.Reflection; global using System.Security.Claims; +global using Contracts.Enumurations; +global using EventBus.Common.Abstractions; \ No newline at end of file diff --git a/crs/Services/Identity/Identity.Application/Identity.Application.csproj b/crs/Services/Identity/Identity.Application/Identity.Application.csproj index fd385fb..3d84051 100644 --- a/crs/Services/Identity/Identity.Application/Identity.Application.csproj +++ b/crs/Services/Identity/Identity.Application/Identity.Application.csproj @@ -8,6 +8,7 @@ + diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommand.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommand.cs index 736bcdc..4ad4588 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommand.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommand.cs @@ -7,6 +7,6 @@ public sealed record RegisterCommand( string FirstName, string LastName, string Role, - string EmailConfirmPagePath, + string Gender, string ReturnUrl ) : ICommand; diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs index 21a9e84..0e5d469 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs @@ -1,16 +1,21 @@ -namespace Identity.Application.Users.Commands.Register; +using Contracts.Services.Identity.Commands; + +namespace Identity.Application.Users.Commands.Register; internal sealed class RegisterCommandHandler( IHashingService hashingService, IIdentityEmailService emailService, IUserRepository userRepository, - IUnitOfWork unitOfWork) - : ICommandHandler + IUnitOfWork unitOfWork, + IMessageBus eventBus) + : Common.Application.Abstractions.Messaging.Command.ICommandHandler { private readonly IHashingService _hashingService = hashingService; private readonly IIdentityEmailService _emailService = emailService; private readonly IUserRepository _userRepository = userRepository; private readonly IUnitOfWork _unitOfWork = unitOfWork; + private readonly IMessageBus _eventBus = eventBus; + public async Task Handle(RegisterCommand request, CancellationToken cancellationToken) { @@ -26,17 +31,15 @@ public async Task Handle(RegisterCommand request, CancellationToken canc await _userRepository.AddUserAsync(user, cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken); - await _emailService.SendConfirmationEmailAsync( - user, - request.EmailConfirmPagePath, - request.ReturnUrl, + await _eventBus.Send( + new UserCreatedConfirmationEmailSendCommand(Guid.NewGuid(), user.Id.Value, request.ReturnUrl), cancellationToken); return Result.Success(); } private async Task> CreateUserResult( - RegisterCommand request , + RegisterCommand request, CancellationToken cancellationToken = default) { var userId = new UserId(Guid.NewGuid()); @@ -52,6 +55,9 @@ private async Task> CreateUserResult( var emailConfirmationToken = _emailService.CreateConfirmationEmailToken(); + var role = Role.FromName(request.Role); + var gender = Gender.FromName(request.Gender); + var isEmailUnique = await _userRepository .IsEmailUnigueAsync(emailResult.Value, cancellationToken); @@ -64,7 +70,8 @@ private async Task> CreateUserResult( passwordSaltResult.Value, emailConfirmationToken, isEmailUnique, - Enum.Parse(request.Role)); + role, + gender); return user; } diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandValidator.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandValidator.cs index 1fb909e..6701cb6 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandValidator.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandValidator.cs @@ -20,17 +20,19 @@ public RegisterCommandValidator() .NotEmpty() .MaximumLength(LastName.MaxLength); - RuleFor(x => x.Role) - .NotEmpty() - .Must(x => Enum.TryParse(x, out _)) - .WithMessage("Role is not valid"); - RuleFor(x => x.ConfirmPassword) .Equal(x => x.Password) .WithMessage("Passwords do not match"); - RuleFor(x => x.EmailConfirmPagePath) - .NotEmpty(); + RuleFor(x => x.Role) + .NotEmpty() + .Must(x => Role.FromName("") is not null) + .WithMessage("Role is not exist"); + + RuleFor(x => x.Gender) + .NotEmpty() + .Must(x => Gender.FromName("") is not null) + .WithMessage("Gender is not exist"); RuleFor(x => x.ReturnUrl); } diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommand.cs b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommand.cs index 6b250a2..2d7e3ae 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommand.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommand.cs @@ -2,5 +2,4 @@ public sealed record RetryConfirmEmailSendCommand( string Email, - string EmailConfirmPagePath, string ReturnUrl) : ICommand; diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs index 16fc293..9a97290 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs @@ -4,7 +4,7 @@ public class RetryConfirmEmailSendCommandHandler( IUserRepository userRepository, IIdentityEmailService emailService, IUnitOfWork unitOfWork) - : ICommandHandler + : Common.Application.Abstractions.Messaging.Command.ICommandHandler { private readonly IUserRepository _userRepository = userRepository; private readonly IIdentityEmailService _emailService = emailService; @@ -33,11 +33,11 @@ public async Task Handle(RetryConfirmEmailSendCommand request, Cancellat RetryEmailConfirmationResult.Error); } - await _emailService.SendConfirmationEmailAsync( - user, - request.EmailConfirmPagePath, - request.ReturnUrl, - cancellationToken); + //await _emailService.SendConfirmationEmailAsync( + // user, + // request.EmailConfirmPagePath, + // request.ReturnUrl, + // cancellationToken); return Result.Success(); } diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryHandler.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryHandler.cs index 8085a00..83c9c9a 100644 --- a/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryHandler.cs @@ -4,7 +4,7 @@ internal sealed class GetRolesQueryHandler : IQueryHandler> Handle(GetRolesQuery request, CancellationToken cancellationToken) { - var roles = Enum.GetNames(typeof(Role)); + var roles = Role.GetNames(); var response = Result.Success(new GetRolesQueryResponse(roles)); return Task.FromResult(response); diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryResponse.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryResponse.cs index 3c471a1..af870b4 100644 --- a/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryResponse.cs +++ b/crs/Services/Identity/Identity.Application/Users/Queries/GetRoles/GetRolesQueryResponse.cs @@ -1,3 +1,3 @@ namespace Identity.Application.Users.Queries.GetRoles; -public record GetRolesQueryResponse(string[] Roles); +public record GetRolesQueryResponse(IEnumerable Roles); diff --git a/crs/Services/Identity/Identity.Domain/GlobalUsings.cs b/crs/Services/Identity/Identity.Domain/GlobalUsings.cs index 3e0e78c..bdb74fc 100644 --- a/crs/Services/Identity/Identity.Domain/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.Domain/GlobalUsings.cs @@ -1,6 +1,5 @@ global using Common.Domain.Primitives.Events; global using Identity.Domain.UserAggregate.DomainEvents; -global using Identity.Domain.UserAggregate.Enums; global using Identity.Domain.UserAggregate.Errors; global using Identity.Domain.UserAggregate.Ids; global using Identity.Domain.UserAggregate.ValueObjects; @@ -8,3 +7,4 @@ global using Common.Domain.Primitives.Results; global using Common.Extensions; global using System.Text.RegularExpressions; +global using Contracts.Enumurations; \ No newline at end of file diff --git a/crs/Services/Identity/Identity.Domain/Identity.Domain.csproj b/crs/Services/Identity/Identity.Domain/Identity.Domain.csproj index e67babe..85e2181 100644 --- a/crs/Services/Identity/Identity.Domain/Identity.Domain.csproj +++ b/crs/Services/Identity/Identity.Domain/Identity.Domain.csproj @@ -12,5 +12,6 @@ + diff --git a/crs/Services/Identity/Identity.Domain/UserAggregate/Enums/Role.cs b/crs/Services/Identity/Identity.Domain/UserAggregate/Enums/Role.cs deleted file mode 100644 index ae61004..0000000 --- a/crs/Services/Identity/Identity.Domain/UserAggregate/Enums/Role.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Identity.Domain.UserAggregate.Enums; - -public enum Role -{ - Admin = 0, - User = 1 -} diff --git a/crs/Services/Identity/Identity.Domain/UserAggregate/User.cs b/crs/Services/Identity/Identity.Domain/UserAggregate/User.cs index dd4612a..2c225c6 100644 --- a/crs/Services/Identity/Identity.Domain/UserAggregate/User.cs +++ b/crs/Services/Identity/Identity.Domain/UserAggregate/User.cs @@ -11,6 +11,7 @@ public sealed class User : AggregateRoot public EmailConfirmationToken EmailConfirmationToken { get; private set; } public bool IsEmailConfirmed { get; private set; } public Role Role { get; private set; } + public Gender Gender { get; private set; } #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. private User() { } @@ -25,7 +26,8 @@ private User( PasswordSalt passwordSalt, EmailConfirmationToken emailConfirmationToken, bool isEmailConfirmed, - Role role) + Role role, + Gender gender) { Id = id; Email = email; @@ -36,6 +38,7 @@ private User( EmailConfirmationToken = emailConfirmationToken; IsEmailConfirmed = isEmailConfirmed; Role = role; + Gender = gender; } public static Result Create( @@ -47,7 +50,8 @@ public static Result Create( PasswordSalt passwordSalt, EmailConfirmationToken emailConfirmationToken, bool isEmailUnique, - Role role) + Role role, + Gender gender) { if (!isEmailUnique) { @@ -64,7 +68,8 @@ public static Result Create( passwordSalt, emailConfirmationToken, isEmailConfirmed: false, - role); + role, + gender); user.AddDomainEvent( new UserCreatedDomainEvent(Guid.NewGuid(), id)); diff --git a/crs/Services/Identity/Identity.Infrastructure/Authentication/JwtProvider.cs b/crs/Services/Identity/Identity.Infrastructure/Authentication/JwtProvider.cs index 799ef93..5b6b670 100644 --- a/crs/Services/Identity/Identity.Infrastructure/Authentication/JwtProvider.cs +++ b/crs/Services/Identity/Identity.Infrastructure/Authentication/JwtProvider.cs @@ -46,7 +46,7 @@ private Claim[] CreateClaims(User user, string audience) => new Claim(JwtRegisteredClaimNames.Aud, audience), new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64), - new Claim(ClaimTypes.Role, user.Role.ToString()) + new Claim(ClaimTypes.Role, (string)user.Role) ]; diff --git a/crs/Services/Identity/Identity.Persistence/Configurations/UserConfiguration.cs b/crs/Services/Identity/Identity.Persistence/Configurations/UserConfiguration.cs index 30782f5..e3623a3 100644 --- a/crs/Services/Identity/Identity.Persistence/Configurations/UserConfiguration.cs +++ b/crs/Services/Identity/Identity.Persistence/Configurations/UserConfiguration.cs @@ -57,5 +57,7 @@ public void Configure(EntityTypeBuilder builder) builder.Property(x => x.IsEmailConfirmed).IsRequired(); builder.Property(x => x.Role).IsRequired(); + + builder.Property(x => x.Gender).IsRequired(); } } diff --git a/crs/Services/Identity/Identity.Presentation/Identity.Presentation.csproj b/crs/Services/Identity/Identity.Presentation/Identity.Presentation.csproj index b1e4b11..df8171f 100644 --- a/crs/Services/Identity/Identity.Presentation/Identity.Presentation.csproj +++ b/crs/Services/Identity/Identity.Presentation/Identity.Presentation.csproj @@ -15,10 +15,4 @@ - - - PreserveNewest - - - diff --git a/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs b/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs index 640a3ec..187c670 100644 --- a/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs +++ b/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs @@ -37,7 +37,7 @@ public async Task Register([FromBody] RegisterRequest request) request.FirstName, request.LastName, request.Role, - EmailConfirmPagePath: $@"{Presentation.AssemblyReference.AssemblyPath}/V1/Templates/ConfirmEmailTemplate.html", + request.Gender, request.ReturnUrl); var result = await _sender.Send(command); @@ -63,7 +63,6 @@ public async Task RetryConfirmEmailSend([FromBody] RetryConfirmEm { var command = new RetryConfirmEmailSendCommand( request.Email, - EmailConfirmPagePath: $@"{Presentation.AssemblyReference.AssemblyPath}/V1/Templates/ConfirmEmailTemplate.html", request.ReturnUrl); var result = await _sender.Send(command); @@ -77,7 +76,7 @@ public async Task ConfirmEmail([FromQuery] ConfirmEmailRequest re var command = new ConfirmEmailCommand(request.UserId, request.EmailConfirmationToken); var result = await _sender.Send(command); - return result.IsSuccess ? Ok() + return result.IsSuccess ? Redirect(request.returnUrl) : HandleFailure(result); } diff --git a/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs b/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs index 85f10c8..5e18f0a 100644 --- a/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs +++ b/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs @@ -2,4 +2,5 @@ public sealed record ConfirmEmailRequest( [Required] Guid UserId, - [Required] string EmailConfirmationToken); + [Required] string EmailConfirmationToken, + [Required] string returnUrl); diff --git a/crs/Services/Identity/Identity.Presentation/V1/Models/RegisterRequest.cs b/crs/Services/Identity/Identity.Presentation/V1/Models/RegisterRequest.cs index f9839ea..17093e0 100644 --- a/crs/Services/Identity/Identity.Presentation/V1/Models/RegisterRequest.cs +++ b/crs/Services/Identity/Identity.Presentation/V1/Models/RegisterRequest.cs @@ -7,4 +7,5 @@ public record RegisterRequest( [Required] string FirstName, [Required] string LastName, [Required] string Role, + [Required] string Gender, [Required] string ReturnUrl); diff --git a/crs/Services/Identity/Identity.Presentation/V1/Templates/ConfirmEmailTemplate.html b/crs/Services/Identity/Identity.Presentation/V1/Templates/ConfirmEmailTemplate.html deleted file mode 100644 index dcfac63..0000000 --- a/crs/Services/Identity/Identity.Presentation/V1/Templates/ConfirmEmailTemplate.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - Email Confirmation - - - -
-

Email Confirmation

-

Hello {{firstName}} {{lastName}},

-

Thank you for signing up. Please click the button below to confirm your email address.

-
- -
-
- - From d16e70ecd63bdd8f0daf51390013a575188453e5 Mon Sep 17 00:00:00 2001 From: Akber Date: Fri, 2 Feb 2024 20:31:46 +0400 Subject: [PATCH 3/7] Add Identity.MessageBus project. --- Eshop.sln | 9 ++++++++- crs/CommonComponents/Contracts/Contracts.csproj | 1 - .../Events/IdentityVerificationConfirmedEvent.cs | 5 +++++ .../Identity.MessageBus/Identity.MessageBus.csproj | 9 +++++++++ 4 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 crs/CommonComponents/Contracts/Services/Identity/Events/IdentityVerificationConfirmedEvent.cs create mode 100644 crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj diff --git a/Eshop.sln b/Eshop.sln index 5eed3f8..8c207cd 100644 --- a/Eshop.sln +++ b/Eshop.sln @@ -75,7 +75,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.MassTransit", "crs EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "crs\CommonComponents\Common\Common.csproj", "{2739BCFE-F0A1-41E4-87CD-66959E1BB75B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Contracts", "crs\CommonComponents\Contracts\Contracts.csproj", "{A367D824-7EB8-4448-A7DC-27BF76576B01}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "crs\CommonComponents\Contracts\Contracts.csproj", "{A367D824-7EB8-4448-A7DC-27BF76576B01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.MessageBus", "crs\Services\Identity\Identity.MessageBus\Identity.MessageBus.csproj", "{9767E75F-8186-4BBE-A81A-E18B1F4687D8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -187,6 +189,10 @@ Global {A367D824-7EB8-4448-A7DC-27BF76576B01}.Debug|Any CPU.Build.0 = Debug|Any CPU {A367D824-7EB8-4448-A7DC-27BF76576B01}.Release|Any CPU.ActiveCfg = Release|Any CPU {A367D824-7EB8-4448-A7DC-27BF76576B01}.Release|Any CPU.Build.0 = Release|Any CPU + {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -227,6 +233,7 @@ Global {8F295CAC-A3B2-41A8-BBFB-B0C5C79BBF91} = {A5847876-AA10-49ED-8C6A-D599FE7348E5} {2739BCFE-F0A1-41E4-87CD-66959E1BB75B} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} {A367D824-7EB8-4448-A7DC-27BF76576B01} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} + {9767E75F-8186-4BBE-A81A-E18B1F4687D8} = {1B13E7AE-01B6-4092-9DD0-1D53F6906791} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {383EFC19-58A6-4418-98E0-23BD0341BA42} diff --git a/crs/CommonComponents/Contracts/Contracts.csproj b/crs/CommonComponents/Contracts/Contracts.csproj index e817cc5..b20aba8 100644 --- a/crs/CommonComponents/Contracts/Contracts.csproj +++ b/crs/CommonComponents/Contracts/Contracts.csproj @@ -13,7 +13,6 @@ - diff --git a/crs/CommonComponents/Contracts/Services/Identity/Events/IdentityVerificationConfirmedEvent.cs b/crs/CommonComponents/Contracts/Services/Identity/Events/IdentityVerificationConfirmedEvent.cs new file mode 100644 index 0000000..e5aec25 --- /dev/null +++ b/crs/CommonComponents/Contracts/Services/Identity/Events/IdentityVerificationConfirmedEvent.cs @@ -0,0 +1,5 @@ +namespace Contracts.Services.Identity.Events; + +public sealed record IdentityVerificationConfirmedEvent( + Guid Id, + Guid UserId) : IntegrationEvent(Id); diff --git a/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj b/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + From d134f137d00b9d0c7c52ba169986e979880b7a56 Mon Sep 17 00:00:00 2001 From: Akber Date: Fri, 2 Feb 2024 21:04:01 +0400 Subject: [PATCH 4/7] Create Email.MessagBus project. --- Email.MessageBus/Email.MessageBus.csproj | 18 ++++++++++++++++++ Email.MessageBus/GlobalUsings.cs | 3 +++ ...eatedConfirmationEmailSendCommandHandler.cs | 10 ++++++++++ Eshop.sln | 7 +++++++ ...UserCreatedConfirmationEmailSendCommand.cs} | 0 .../Email.Application/Email.Application.csproj | 4 ++++ .../SendConfirmationUserMessageCommand.cs | 3 +++ ...endConfirmationUserMessageCommandHandler.cs | 3 +++ .../Identity.MessageBus.csproj | 5 +++++ 9 files changed, 53 insertions(+) create mode 100644 Email.MessageBus/Email.MessageBus.csproj create mode 100644 Email.MessageBus/GlobalUsings.cs create mode 100644 Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs rename crs/CommonComponents/Contracts/Services/Identity/Commands/{UserCreatedConfirmationEmailSentCommand.cs => UserCreatedConfirmationEmailSendCommand.cs} (100%) create mode 100644 crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs create mode 100644 crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs diff --git a/Email.MessageBus/Email.MessageBus.csproj b/Email.MessageBus/Email.MessageBus.csproj new file mode 100644 index 0000000..4758760 --- /dev/null +++ b/Email.MessageBus/Email.MessageBus.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/Email.MessageBus/GlobalUsings.cs b/Email.MessageBus/GlobalUsings.cs new file mode 100644 index 0000000..5b4d468 --- /dev/null +++ b/Email.MessageBus/GlobalUsings.cs @@ -0,0 +1,3 @@ +global using EventBus.MassTransit.Handlers; +global using Contracts.Services.Identity.Commands; +global using MassTransit; \ No newline at end of file diff --git a/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs b/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs new file mode 100644 index 0000000..fdd1746 --- /dev/null +++ b/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs @@ -0,0 +1,10 @@ +namespace Email.MessageBus.Handlers.Commands; + +public sealed class UserCreatedConfirmationEmailSendCommandHandler + : IntegrationCommandHandler +{ + public override Task Handle(ConsumeContext context) + { + throw new NotImplementedException(); + } +} diff --git a/Eshop.sln b/Eshop.sln index 8c207cd..e4ca15a 100644 --- a/Eshop.sln +++ b/Eshop.sln @@ -79,6 +79,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "crs\CommonComp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.MessageBus", "crs\Services\Identity\Identity.MessageBus\Identity.MessageBus.csproj", "{9767E75F-8186-4BBE-A81A-E18B1F4687D8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Email.MessageBus", "Email.MessageBus\Email.MessageBus.csproj", "{9D125B77-F05C-40F7-A42A-5B957C48203E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -193,6 +195,10 @@ Global {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.Build.0 = Release|Any CPU + {9D125B77-F05C-40F7-A42A-5B957C48203E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D125B77-F05C-40F7-A42A-5B957C48203E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D125B77-F05C-40F7-A42A-5B957C48203E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D125B77-F05C-40F7-A42A-5B957C48203E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -234,6 +240,7 @@ Global {2739BCFE-F0A1-41E4-87CD-66959E1BB75B} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} {A367D824-7EB8-4448-A7DC-27BF76576B01} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} {9767E75F-8186-4BBE-A81A-E18B1F4687D8} = {1B13E7AE-01B6-4092-9DD0-1D53F6906791} + {9D125B77-F05C-40F7-A42A-5B957C48203E} = {7CFB86E0-426D-4822-A84E-D2BC5987D187} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {383EFC19-58A6-4418-98E0-23BD0341BA42} diff --git a/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs b/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs similarity index 100% rename from crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSentCommand.cs rename to crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs diff --git a/crs/Services/Email/Email.Application/Email.Application.csproj b/crs/Services/Email/Email.Application/Email.Application.csproj index bfecdf3..f80eba6 100644 --- a/crs/Services/Email/Email.Application/Email.Application.csproj +++ b/crs/Services/Email/Email.Application/Email.Application.csproj @@ -5,4 +5,8 @@ enable enable + + + + diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs new file mode 100644 index 0000000..065c0db --- /dev/null +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs @@ -0,0 +1,3 @@ +namespace Email.Application.Emails.Commands.SendConfirmationUserMessage; + +public sealed record SendConfirmationUserMessageCommand(Guid UserId, string ReturnUrl); diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs new file mode 100644 index 0000000..82855cf --- /dev/null +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs @@ -0,0 +1,3 @@ +namespace Email.Application.Emails.Commands.SendConfirmationUserMessage; + +public sealed record SendConfirmationUserMessageCommandHandler(Guid userId); diff --git a/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj b/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj index fa71b7a..8d4c53b 100644 --- a/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj +++ b/crs/Services/Identity/Identity.MessageBus/Identity.MessageBus.csproj @@ -6,4 +6,9 @@ enable + + + + + From 799bf897b004302685dd4c6d353c73026cf981ec Mon Sep 17 00:00:00 2001 From: Akber Date: Fri, 2 Feb 2024 21:43:06 +0400 Subject: [PATCH 5/7] Add Base email logic in Email.Infrasctructure. --- .../Application/Abstractions/IEmailService.cs | 17 ----------------- .../UserCreatedConfirmationEmailSendCommand.cs | 3 ++- .../EventBus.Common/Abstractions/IMessageBus.cs | 4 ++-- .../Email.Application/Email.Application.csproj | 5 +++++ .../SendConfirmationUserMessageCommand.cs | 2 +- ...SendConfirmationUserMessageCommandHandler.cs | 11 ++++++++++- .../Email/Email.Application/GlobalUsings.cs | 3 +++ .../Email/Abstractions/IEmailService.cs | 6 ++++++ .../Email/Abstractions/IIdentityEmailService.cs | 6 ++++++ .../Models/SendConfirmationEmailRequest.cs | 10 ++++++++++ .../EmailBaseService.cs} | 2 +- .../Email/Services/IdentityEmailService.cs | 8 ++++++++ .../Users/Commands/Login/LoginCommandHandler.cs | 3 ++- .../Commands/Register/RegisterCommandHandler.cs | 8 ++++---- .../RetryConfirmEmailSendCommandHandler.cs | 6 ++---- 15 files changed, 62 insertions(+), 32 deletions(-) delete mode 100644 crs/CommonComponents/Common/Application/Abstractions/IEmailService.cs create mode 100644 crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs create mode 100644 crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs rename crs/Services/Email/Email.Infrastructure/Email/{EmailService.cs => Services/EmailBaseService.cs} (91%) create mode 100644 crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs diff --git a/crs/CommonComponents/Common/Application/Abstractions/IEmailService.cs b/crs/CommonComponents/Common/Application/Abstractions/IEmailService.cs deleted file mode 100644 index d616caa..0000000 --- a/crs/CommonComponents/Common/Application/Abstractions/IEmailService.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Common.Application.Abstractions; - -/// -/// Interface for email service. -/// -public interface IEmailService -{ - /// - /// Send email async. - /// - /// The email address to send to. - /// The email subject. - /// The email body. - /// The . - /// A representing the asynchronous operation. - Task SendAsync(string to, string subject, string body, CancellationToken cancellationToken = default); -} diff --git a/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs b/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs index decbaa8..6f07dca 100644 --- a/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs +++ b/crs/CommonComponents/Contracts/Services/Identity/Commands/UserCreatedConfirmationEmailSendCommand.cs @@ -3,4 +3,5 @@ public sealed record UserCreatedConfirmationEmailSendCommand( Guid Id, Guid UserId, - string returnUrl) : IntegrationCommand(Id); + string ConfirmationEmailToken, + string ReturnUrl) : IntegrationCommand(Id); diff --git a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs index c0886b7..63a2220 100644 --- a/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs +++ b/crs/CommonComponents/EventBus/EventBus.Common/Abstractions/IMessageBus.cs @@ -6,7 +6,7 @@ public interface IMessageBus { /// - /// Publish event. + /// Publish event to the bus. /// /// The event. /// The cancellation token. @@ -15,7 +15,7 @@ Task Publish(TEvent @event, CancellationToken cancellationToken = defaul where TEvent : IIntegrationEvent; /// - /// Send command. + /// Send command to the bus. /// /// The command. /// The cancellation token. diff --git a/crs/Services/Email/Email.Application/Email.Application.csproj b/crs/Services/Email/Email.Application/Email.Application.csproj index f80eba6..ac04d7d 100644 --- a/crs/Services/Email/Email.Application/Email.Application.csproj +++ b/crs/Services/Email/Email.Application/Email.Application.csproj @@ -9,4 +9,9 @@ + + + + + diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs index 065c0db..df4c90c 100644 --- a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommand.cs @@ -1,3 +1,3 @@ namespace Email.Application.Emails.Commands.SendConfirmationUserMessage; -public sealed record SendConfirmationUserMessageCommand(Guid UserId, string ReturnUrl); +public sealed record SendConfirmationUserMessageCommand(Guid UserId, string ReturnUrl) : ICommand; diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs index 82855cf..fd46a8b 100644 --- a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs @@ -1,3 +1,12 @@ namespace Email.Application.Emails.Commands.SendConfirmationUserMessage; -public sealed record SendConfirmationUserMessageCommandHandler(Guid userId); +internal sealed class SendConfirmationUserMessageCommandHandler(IEmailService emailService) + : ICommandHandler +{ + private readonly IEmailService _emailService = emailService; + + public Task Handle(SendConfirmationUserMessageCommand request, CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } +} diff --git a/crs/Services/Email/Email.Application/GlobalUsings.cs b/crs/Services/Email/Email.Application/GlobalUsings.cs index 925a4c7..b40ad76 100644 --- a/crs/Services/Email/Email.Application/GlobalUsings.cs +++ b/crs/Services/Email/Email.Application/GlobalUsings.cs @@ -1 +1,4 @@ global using System.Reflection; +global using Common.Application.Abstractions.Messaging.Command; +global using Common.Domain.Primitives.Results; +global using Email.Infrastructure.Email.Abstractions; \ No newline at end of file diff --git a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs index 80846b9..a6a6941 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs @@ -2,5 +2,11 @@ public interface IEmailService { + /// + /// Send email async. + /// + /// The . + /// The . + /// Task SendAsync(SendMessageRequest request, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs new file mode 100644 index 0000000..ff50782 --- /dev/null +++ b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs @@ -0,0 +1,6 @@ +namespace Email.Infrastructure.Email.Abstractions; + +public interface IIdentityEmailService : IEmailService +{ + Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnUrl, CancellationToken cancellationToken = default); +} diff --git a/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs b/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs new file mode 100644 index 0000000..3c10311 --- /dev/null +++ b/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs @@ -0,0 +1,10 @@ +namespace Email.Infrastructure.Email.Models; + +public record SendConfirmationEmailRequest( + string FirstName, + string LastName, + string Email, + string EmailConfirmationToken, + string ReturnUrl, + string EmailConfirmPagePath + ); diff --git a/crs/Services/Email/Email.Infrastructure/Email/EmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs similarity index 91% rename from crs/Services/Email/Email.Infrastructure/Email/EmailService.cs rename to crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs index 2889d65..303d4ca 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/EmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs @@ -1,6 +1,6 @@ namespace Email.Infrastructure.Email; -public class EmailService(IOptions options) : IEmailService +public abstract class EmailBaseService(IOptions options) : IEmailService { private readonly EmailOptions _options = options.Value; diff --git a/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs new file mode 100644 index 0000000..5c2ae5a --- /dev/null +++ b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs @@ -0,0 +1,8 @@ +namespace Email.Infrastructure.Email.Services; + +public class IdentityEmailService : EmailBaseService, IIdentityEmailService +{ + public Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnUrl, CancellationToken cancellationToken = default) + { + } +} diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Login/LoginCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Login/LoginCommandHandler.cs index 847eaf2..019c055 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Login/LoginCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Login/LoginCommandHandler.cs @@ -36,6 +36,7 @@ public async Task> Handle(LoginCommand request, Canc var userToken = _jwtProvider.CreateTokenString(user, request.Audience); await _unitOfWork.SaveChangesAsync(cancellationToken); + return new LoginCommanResponse(userToken, refreshToken.Token); } @@ -45,7 +46,7 @@ public async Task> Handle(LoginCommand request, Canc return await _userRepository.GetUserByEmailAsync(emailResult.Value, cancellationToken); } - private Result Login(User user ,string password) + private Result Login(User user, string password) { var passwordIsCorrect = _hashingService.Verify( password, user.PasswordSalt.Value, user.PasswordHash.Value); diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs index 0e5d469..e82a77a 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs @@ -8,7 +8,7 @@ internal sealed class RegisterCommandHandler( IUserRepository userRepository, IUnitOfWork unitOfWork, IMessageBus eventBus) - : Common.Application.Abstractions.Messaging.Command.ICommandHandler + : ICommandHandler { private readonly IHashingService _hashingService = hashingService; private readonly IIdentityEmailService _emailService = emailService; @@ -19,7 +19,7 @@ internal sealed class RegisterCommandHandler( public async Task Handle(RegisterCommand request, CancellationToken cancellationToken) { - var userResult = await CreateUserResult(request); + var userResult = await CreateUserResultAsync(request, cancellationToken); if (userResult.IsFailure) { @@ -32,13 +32,13 @@ public async Task Handle(RegisterCommand request, CancellationToken canc await _unitOfWork.SaveChangesAsync(cancellationToken); await _eventBus.Send( - new UserCreatedConfirmationEmailSendCommand(Guid.NewGuid(), user.Id.Value, request.ReturnUrl), + new UserCreatedConfirmationEmailSendCommand(Guid.NewGuid(), user.Id.Value, user.EmailConfirmationToken, request.ReturnUrl), cancellationToken); return Result.Success(); } - private async Task> CreateUserResult( + private async Task> CreateUserResultAsync( RegisterCommand request, CancellationToken cancellationToken = default) { diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs index 9a97290..2f3d78d 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs @@ -2,13 +2,11 @@ public class RetryConfirmEmailSendCommandHandler( IUserRepository userRepository, - IIdentityEmailService emailService, - IUnitOfWork unitOfWork) - : Common.Application.Abstractions.Messaging.Command.ICommandHandler + IIdentityEmailService emailService) + : ICommandHandler { private readonly IUserRepository _userRepository = userRepository; private readonly IIdentityEmailService _emailService = emailService; - private readonly IUnitOfWork _unitOfWork = unitOfWork; public async Task Handle(RetryConfirmEmailSendCommand request, CancellationToken cancellationToken) { From c1895536af7e6dd0a4a0445891e48dfbba3df6d5 Mon Sep 17 00:00:00 2001 From: Akber Date: Mon, 5 Feb 2024 15:07:59 +0400 Subject: [PATCH 6/7] Add grpc layer in identity project. Add login in identity.proto. Add Configurations logic in email project --- Eshop.sln | 21 ++++++++----- .../Contracts/Abstractions/Abstractions.proto | 10 ------- .../Contracts/Enumurations/Gender.cs | 6 ++-- .../Contracts/Enumurations/Role.cs | 4 +-- .../Services/Identity/Identity.proto | 27 ++++++++++++----- .../TelemetryServiceInstaller.cs | 3 +- crs/Services/Catalog/Catalog.App/Startup.cs | 12 ++------ .../ApplicationServiceInstaller.cs | 17 +++++++++++ ...enticationAuthorizationServiceInstaller.cs | 9 ++++++ .../DocumentationServiceInstaller.cs | 17 +++++++++++ .../InfrastructureServiceInstaller.cs | 15 ++++++++++ .../Configurations/LoggingServiceInstaller.cs | 9 ++++++ .../MessageBusServiceInstaller.cs | 9 ++++++ .../PresentationServiceInstaller.cs | 16 ++++++++++ .../TelemetryServiceInstaller.cs | 12 ++++++++ crs/Services/Email/Email.App/Email.App.csproj | 7 ++--- crs/Services/Email/Email.App/GlobalUsings.cs | 5 ++++ .../OptionsSetup/EmailOptionsSetup.cs | 4 +-- crs/Services/Email/Email.App/Startup.cs | 30 +++++-------------- crs/Services/Email/Email.App/appsettings.yml | 4 +++ ...ndConfirmationUserMessageCommandHandler.cs | 17 +++++++++-- .../Email.Infrastructure.csproj | 4 +++ .../Abstractions/IIdentityEmailService.cs | 2 +- .../Email/EmailTemplatePath.cs | 16 ++++++++++ .../Models/SendConfirmationEmailRequest.cs | 2 ++ .../Email/Services/IdentityEmailService.cs | 30 +++++++++++++++++-- .../Email.Infrastructure/GlobalUsings.cs | 3 +- .../Email.MessageBus}/Email.MessageBus.csproj | 4 +-- .../Email/Email.MessageBus}/GlobalUsings.cs | 0 ...atedConfirmationEmailSendCommandHandler.cs | 0 .../Email.Templates/AssemblyReference.cs | 1 + .../Idenitty.Grpc/Idenitty.Grpc.csproj | 9 ++++++ .../InfrastructureServiceInstaller.cs | 2 -- ...aller.cs => MessageBusServiceInstaller.cs} | 2 +- crs/Services/Identity/Identity.App/Startup.cs | 10 ++----- .../AssemblyReference.cs | 1 - .../V1/Controllers/UserController.cs | 2 +- .../V1/Models/ConfirmEmailRequest.cs | 2 +- 38 files changed, 251 insertions(+), 93 deletions(-) create mode 100644 crs/Services/Email/Email.App/Configurations/ApplicationServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/DocumentationServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/InfrastructureServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/LoggingServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/MessageBusServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/PresentationServiceInstaller.cs create mode 100644 crs/Services/Email/Email.App/Configurations/TelemetryServiceInstaller.cs create mode 100644 crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs rename {Email.MessageBus => crs/Services/Email/Email.MessageBus}/Email.MessageBus.csproj (60%) rename {Email.MessageBus => crs/Services/Email/Email.MessageBus}/GlobalUsings.cs (100%) rename {Email.MessageBus => crs/Services/Email/Email.MessageBus}/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs (100%) create mode 100644 crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj rename crs/Services/Identity/Identity.App/Configurations/{EventBusServiceInstaller.cs => MessageBusServiceInstaller.cs} (92%) diff --git a/Eshop.sln b/Eshop.sln index e4ca15a..825e572 100644 --- a/Eshop.sln +++ b/Eshop.sln @@ -77,9 +77,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "crs\CommonCompone EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Contracts", "crs\CommonComponents\Contracts\Contracts.csproj", "{A367D824-7EB8-4448-A7DC-27BF76576B01}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Identity.MessageBus", "crs\Services\Identity\Identity.MessageBus\Identity.MessageBus.csproj", "{9767E75F-8186-4BBE-A81A-E18B1F4687D8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.MessageBus", "crs\Services\Identity\Identity.MessageBus\Identity.MessageBus.csproj", "{9767E75F-8186-4BBE-A81A-E18B1F4687D8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Email.MessageBus", "Email.MessageBus\Email.MessageBus.csproj", "{9D125B77-F05C-40F7-A42A-5B957C48203E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Email.MessageBus", "crs\Services\Email\Email.MessageBus\Email.MessageBus.csproj", "{492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Idenitty.Grpc", "crs\Services\Identity\Idenitty.Grpc\Idenitty.Grpc.csproj", "{1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -195,10 +197,14 @@ Global {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {9767E75F-8186-4BBE-A81A-E18B1F4687D8}.Release|Any CPU.Build.0 = Release|Any CPU - {9D125B77-F05C-40F7-A42A-5B957C48203E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9D125B77-F05C-40F7-A42A-5B957C48203E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9D125B77-F05C-40F7-A42A-5B957C48203E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9D125B77-F05C-40F7-A42A-5B957C48203E}.Release|Any CPU.Build.0 = Release|Any CPU + {492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB}.Release|Any CPU.Build.0 = Release|Any CPU + {1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -240,7 +246,8 @@ Global {2739BCFE-F0A1-41E4-87CD-66959E1BB75B} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} {A367D824-7EB8-4448-A7DC-27BF76576B01} = {18B99957-5BAF-4D5D-BC24-27EB1B42DB1B} {9767E75F-8186-4BBE-A81A-E18B1F4687D8} = {1B13E7AE-01B6-4092-9DD0-1D53F6906791} - {9D125B77-F05C-40F7-A42A-5B957C48203E} = {7CFB86E0-426D-4822-A84E-D2BC5987D187} + {492C4BC4-B89A-4E5C-B9F0-FC7A03BFE1FB} = {7CFB86E0-426D-4822-A84E-D2BC5987D187} + {1DEB0D00-7A0F-4F76-85CA-75E2DDA390B5} = {1B13E7AE-01B6-4092-9DD0-1D53F6906791} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {383EFC19-58A6-4418-98E0-23BD0341BA42} diff --git a/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto index 031c73c..73d6be8 100644 --- a/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto +++ b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto @@ -2,15 +2,5 @@ syntax = "proto3"; package Contracts.Abstractions.Protobuf; -message GetResponse{ - oneof OneOf{ - google.protobuf.Any Projection = 1; - NotFound NotFound = 2; - } -} message NotFound {} - -message Result { - -} \ No newline at end of file diff --git a/crs/CommonComponents/Contracts/Enumurations/Gender.cs b/crs/CommonComponents/Contracts/Enumurations/Gender.cs index 16773d0..4a2e075 100644 --- a/crs/CommonComponents/Contracts/Enumurations/Gender.cs +++ b/crs/CommonComponents/Contracts/Enumurations/Gender.cs @@ -2,7 +2,7 @@ public class Gender(int value, string name) : Enumeration(value, name) { - public static readonly Gender Male = new(1, nameof(Male)); - public static readonly Gender Female = new(2, nameof(Female)); - public static readonly Gender Undefined = new(3, nameof(Undefined)); + public static readonly Gender Male = new(0, nameof(Male)); + public static readonly Gender Female = new(1, nameof(Female)); + public static readonly Gender Undefined = new(2, nameof(Undefined)); } diff --git a/crs/CommonComponents/Contracts/Enumurations/Role.cs b/crs/CommonComponents/Contracts/Enumurations/Role.cs index 63c58c8..3248594 100644 --- a/crs/CommonComponents/Contracts/Enumurations/Role.cs +++ b/crs/CommonComponents/Contracts/Enumurations/Role.cs @@ -3,6 +3,6 @@ public class Role(int value, string name) : Enumeration(value, name) { - public static readonly Role User = new(1, nameof(User)); - public static readonly Role Admin = new(2, nameof(Admin)); + public static readonly Role User = new(0, nameof(User)); + public static readonly Role Admin = new(1, nameof(Admin)); } diff --git a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto index 0dece2f..41bc837 100644 --- a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto +++ b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto @@ -5,19 +5,30 @@ package Contracts.Services.Idenitty.Protobuf; import "Abstractions/Abstractions.proto"; service IdenittyService { - rpc GetUser(GetUserRequest) returns (Abstractions.Protobuf.GetResponse); + rpc GetUser(GetUserRequest) returns (User); } message GetUserRequest { - string Id = 1; + string id = 1; } -message GetUserResponse { - oneof OneOf{ - User - } +message UserDetails { + string user_id = 1; + string email = 3; + string first_name = 2; + string last_name = 2; + bool is_email_confirmed = 4; + Role role = 5; + Gender gender = 6; } -message User { - string +enum Role { + USER = 0; + ADMIN = 1; +} + +enum Gender { + MALE = 0; + FEMALE = 1; + UNDEFINED = 2; } \ No newline at end of file diff --git a/crs/Services/Catalog/Catalog.App/Configurations/TelemetryServiceInstaller.cs b/crs/Services/Catalog/Catalog.App/Configurations/TelemetryServiceInstaller.cs index 9dc688c..ba32763 100644 --- a/crs/Services/Catalog/Catalog.App/Configurations/TelemetryServiceInstaller.cs +++ b/crs/Services/Catalog/Catalog.App/Configurations/TelemetryServiceInstaller.cs @@ -5,8 +5,7 @@ internal sealed class TelemetryServiceInstaller : IServiceInstaller public void Install(IServiceCollection services, IConfiguration configuration) => services .AddOpenTelemetry() - .WithMetrics(options => - options + .WithMetrics(options => options .AddPrometheusExporter() .AddHttpClientInstrumentation() .AddRuntimeInstrumentation()); diff --git a/crs/Services/Catalog/Catalog.App/Startup.cs b/crs/Services/Catalog/Catalog.App/Startup.cs index 10c9c12..4b7bc69 100644 --- a/crs/Services/Catalog/Catalog.App/Startup.cs +++ b/crs/Services/Catalog/Catalog.App/Startup.cs @@ -1,17 +1,11 @@ -using Microsoft.Extensions.Options; - -namespace Catalog.App; +namespace Catalog.App; public sealed class Startup(IConfiguration configuration) { private readonly IConfiguration _configuration = configuration; - public void ConfigureServices(IServiceCollection services) - { - services.InstallServicesFromAssembly( - _configuration, - App.AssemblyReference.Assembly); - } + public void ConfigureServices(IServiceCollection services) => + services.InstallServicesFromAssembly(_configuration, App.AssemblyReference.Assembly); public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { diff --git a/crs/Services/Email/Email.App/Configurations/ApplicationServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/ApplicationServiceInstaller.cs new file mode 100644 index 0000000..18a37c0 --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/ApplicationServiceInstaller.cs @@ -0,0 +1,17 @@ +namespace Email.App.Configurations; + +internal sealed class ApplicationServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.AddMediatR(configuration => configuration + .RegisterServicesFromAssembly(Application.AssemblyReference.Assembly) + .AddOpenBehavior(typeof(LoggingPipelineBehavior<,>)) + .AddOpenBehavior(typeof(ValidationPipelineBehavior<,>)) + ); + + services.AddValidatorsFromAssembly( + Application.AssemblyReference.Assembly, + includeInternalTypes: true); + } +} diff --git a/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs new file mode 100644 index 0000000..88e8990 --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/AuthenticationAuthorizationServiceInstaller.cs @@ -0,0 +1,9 @@ +namespace Email.App.Configurations; + +internal sealed class AuthenticationAuthorizationServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + + } +} diff --git a/crs/Services/Email/Email.App/Configurations/DocumentationServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/DocumentationServiceInstaller.cs new file mode 100644 index 0000000..7269395 --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/DocumentationServiceInstaller.cs @@ -0,0 +1,17 @@ +namespace Email.App.Configurations; + +internal sealed class DocumentationServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.AddMediatR(configuration => configuration + .RegisterServicesFromAssembly(Application.AssemblyReference.Assembly) + .AddOpenBehavior(typeof(LoggingPipelineBehavior<,>)) + .AddOpenBehavior(typeof(ValidationPipelineBehavior<,>)) + ); + + services.AddValidatorsFromAssembly( + Application.AssemblyReference.Assembly, + includeInternalTypes: true); + } +} diff --git a/crs/Services/Email/Email.App/Configurations/InfrastructureServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/InfrastructureServiceInstaller.cs new file mode 100644 index 0000000..6ef9fae --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/InfrastructureServiceInstaller.cs @@ -0,0 +1,15 @@ +namespace Email.App.Configurations; + +internal sealed class InfrastructureServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.Scan(services => services + .FromAssemblies(Infrastructure.AssemblyReference.Assembly) + .AddClasses(false) + .AsImplementedInterfaces() + .WithScopedLifetime()); + + services.ConfigureOptions(); + } +} diff --git a/crs/Services/Email/Email.App/Configurations/LoggingServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/LoggingServiceInstaller.cs new file mode 100644 index 0000000..14a57ca --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/LoggingServiceInstaller.cs @@ -0,0 +1,9 @@ +namespace Email.App.Configurations; + +internal sealed class LoggingServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + + } +} diff --git a/crs/Services/Email/Email.App/Configurations/MessageBusServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/MessageBusServiceInstaller.cs new file mode 100644 index 0000000..4df60c6 --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/MessageBusServiceInstaller.cs @@ -0,0 +1,9 @@ +namespace Email.App.Configurations; + +internal sealed class MessageBusServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + + } +} diff --git a/crs/Services/Email/Email.App/Configurations/PresentationServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/PresentationServiceInstaller.cs new file mode 100644 index 0000000..738e2cb --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/PresentationServiceInstaller.cs @@ -0,0 +1,16 @@ +namespace Email.App.Configurations; + +internal sealed class PresentationServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.AddCors(options => + { + options.AddPolicy(SD.DefaultCorsPolicyName, + builder => builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader()); + }); + } +} diff --git a/crs/Services/Email/Email.App/Configurations/TelemetryServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/TelemetryServiceInstaller.cs new file mode 100644 index 0000000..56f9d4b --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/TelemetryServiceInstaller.cs @@ -0,0 +1,12 @@ +namespace Email.App.Configurations; + +internal sealed class TelemetryServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) => + services + .AddOpenTelemetry() + .WithMetrics(options => options + .AddPrometheusExporter() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation()); +} diff --git a/crs/Services/Email/Email.App/Email.App.csproj b/crs/Services/Email/Email.App/Email.App.csproj index f5d489e..0f52a74 100644 --- a/crs/Services/Email/Email.App/Email.App.csproj +++ b/crs/Services/Email/Email.App/Email.App.csproj @@ -11,6 +11,7 @@ + @@ -18,15 +19,13 @@ + + - - - - diff --git a/crs/Services/Email/Email.App/GlobalUsings.cs b/crs/Services/Email/Email.App/GlobalUsings.cs index e0f6ddc..55dfe3a 100644 --- a/crs/Services/Email/Email.App/GlobalUsings.cs +++ b/crs/Services/Email/Email.App/GlobalUsings.cs @@ -3,3 +3,8 @@ global using System.Reflection; global using Email.App; global using Email.Infrastructure.Email; +global using Common.App.Extensions; +global using Common.Application.Behaviors; +global using FluentValidation; +global using Email.App.OptionsSetup; +global using Common.Infrastructure.Middleware; diff --git a/crs/Services/Email/Email.App/OptionsSetup/EmailOptionsSetup.cs b/crs/Services/Email/Email.App/OptionsSetup/EmailOptionsSetup.cs index c524d09..ee4a79b 100644 --- a/crs/Services/Email/Email.App/OptionsSetup/EmailOptionsSetup.cs +++ b/crs/Services/Email/Email.App/OptionsSetup/EmailOptionsSetup.cs @@ -4,8 +4,6 @@ internal sealed class EmailOptionsSetup(IConfiguration configuration) : IConfigu { private readonly IConfiguration _configuration = configuration; - public void Configure(EmailOptions options) - { + public void Configure(EmailOptions options) => _configuration.GetSection(SD.EmailSectionKey).Bind(options); - } } diff --git a/crs/Services/Email/Email.App/Startup.cs b/crs/Services/Email/Email.App/Startup.cs index 8e2ac05..37c6da9 100644 --- a/crs/Services/Email/Email.App/Startup.cs +++ b/crs/Services/Email/Email.App/Startup.cs @@ -1,29 +1,11 @@ namespace Email.App; -public class Startup(IConfiguration configuration) +public sealed class Startup(IConfiguration configuration) { private readonly IConfiguration _configuration = configuration; - public void ConfigureServices(IServiceCollection services) - { - //services - // .AddOpenTelemetry() - // .WithMetrics(options => options - // .AddPrometheusExporter() - // .AddHttpClientInstrumentation() - // .AddRuntimeInstrumentation()); - - //services.AddTransient(); - - services.AddCors(options => - { - options.AddPolicy(SD.DefaultCorsPolicyName, - builder => builder - .AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader()); - }); - } + public void ConfigureServices(IServiceCollection services) => + services.InstallServicesFromAssembly(_configuration, App.AssemblyReference.Assembly); public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { @@ -31,8 +13,10 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseDeveloperExceptionPage(); app.UseSwagger(); - app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Email.App v1")); + app.UseSwaggerUI(); } + + app.UseMiddleware(); app.UseHttpsRedirection(); @@ -43,7 +27,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseEndpoints(endpoints => { endpoints.MapControllers(); - //endpoints.MapPrometheusScrapingEndpoint(); + endpoints.MapPrometheusScrapingEndpoint(); }); } } diff --git a/crs/Services/Email/Email.App/appsettings.yml b/crs/Services/Email/Email.App/appsettings.yml index 3a1420d..a113568 100644 --- a/crs/Services/Email/Email.App/appsettings.yml +++ b/crs/Services/Email/Email.App/appsettings.yml @@ -10,4 +10,8 @@ Email: Username: akber.sharifov2004@gmail.com Password: ueey qfia bnyx atce + +Swagger: + Title: "Email API" + AllowedHosts: "*" \ No newline at end of file diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs index fd46a8b..416c904 100644 --- a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs @@ -1,12 +1,23 @@ namespace Email.Application.Emails.Commands.SendConfirmationUserMessage; -internal sealed class SendConfirmationUserMessageCommandHandler(IEmailService emailService) +internal sealed class SendConfirmationUserMessageCommandHandler(IIdentityEmailService emailService) : ICommandHandler { - private readonly IEmailService _emailService = emailService; + private readonly IIdentityEmailService _emailService = emailService; + private readonly I + public Task Handle(SendConfirmationUserMessageCommand request, CancellationToken cancellationToken) { - throw new NotImplementedException(); + _emailService.SendConfirmationEmailAsync( + new SendConfirmationEmailRequest + { + UserId = request.UserId, + EmailConfirmationToken = request.EmailConfirmationToken, + ReturnUrl = request.ReturnUrl, + FirstName = request.FirstName, + LastName = request.LastName, + Email = request.Email + }, cancellationToken); } } diff --git a/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj b/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj index 4b7d4fc..4ab33d7 100644 --- a/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj +++ b/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj @@ -12,4 +12,8 @@ + + + + diff --git a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs index ff50782..6d33beb 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IIdentityEmailService.cs @@ -2,5 +2,5 @@ public interface IIdentityEmailService : IEmailService { - Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnUrl, CancellationToken cancellationToken = default); + Task SendConfirmationEmailAsync(SendConfirmationEmailRequest request, CancellationToken cancellationToken = default); } diff --git a/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs b/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs new file mode 100644 index 0000000..c19ecc4 --- /dev/null +++ b/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs @@ -0,0 +1,16 @@ +namespace Email.Infrastructure.Email; + +/// +/// This class is used to get the path of the email templates. +/// +public static class EmailTemplatePath +{ + /// + /// required change this template: {{firstName}}, {{lastName}}, {{confirmationLink}} + /// + public static string ConfirmEmailTemplate => GetTemplatePath("ConfirmEmailTemplate.html"); + + + private static string GetTemplatePath(string templateName) => + Path.Combine(Templates.AssemblyReference.AssemblyPath, "Templates", templateName); +} diff --git a/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs b/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs index 3c10311..d582280 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Models/SendConfirmationEmailRequest.cs @@ -3,8 +3,10 @@ public record SendConfirmationEmailRequest( string FirstName, string LastName, + string UserId, string Email, string EmailConfirmationToken, string ReturnUrl, + string Subject, string EmailConfirmPagePath ); diff --git a/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs index 5c2ae5a..caeaf77 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs @@ -1,8 +1,34 @@ namespace Email.Infrastructure.Email.Services; -public class IdentityEmailService : EmailBaseService, IIdentityEmailService +internal sealed class IdentityEmailService + (IOptions options) : + EmailBaseService(options), + IIdentityEmailService { - public Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnUrl, CancellationToken cancellationToken = default) + public async Task SendConfirmationEmailAsync(SendConfirmationEmailRequest request, CancellationToken cancellationToken = default) { + var confirmEmailTemplatePath = EmailTemplatePath.ConfirmEmailTemplate; + + string confirmEmailTemplate = + await File.ReadAllTextAsync(confirmEmailTemplatePath, cancellationToken); + + var confirmUrl = + $@"{thi}?UserId={request.UserId}&EmailConfirmationToken={request.EmailConfirmationToken}&ReturnUrl={request.ReturnUrl}"; + + var confirmUrlEncode = HtmlEncoder.Default.Encode(confirmUrl); + + confirmEmailTemplate = + confirmEmailTemplate + .Replace("{{firstName}}", request.FirstName) + .Replace("{{lastName}}", request.LastName) + .Replace("{{confirmationLink}}", confirmUrlEncode); + + var sendMessageRequest = new SendMessageRequest( + To: request.Email, + Subject: request.Subject, + Body: confirmEmailTemplate + ); + + await SendAsync(sendMessageRequest, cancellationToken); } } diff --git a/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs b/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs index 341f5e2..17abbbd 100644 --- a/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs +++ b/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs @@ -4,4 +4,5 @@ global using Microsoft.Extensions.Options; global using MimeKit; global using MailKit.Net.Smtp; -global using System.Reflection; \ No newline at end of file +global using System.Reflection; +global using System.Text.Encodings.Web; \ No newline at end of file diff --git a/Email.MessageBus/Email.MessageBus.csproj b/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj similarity index 60% rename from Email.MessageBus/Email.MessageBus.csproj rename to crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj index 4758760..8b77fed 100644 --- a/Email.MessageBus/Email.MessageBus.csproj +++ b/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/Email.MessageBus/GlobalUsings.cs b/crs/Services/Email/Email.MessageBus/GlobalUsings.cs similarity index 100% rename from Email.MessageBus/GlobalUsings.cs rename to crs/Services/Email/Email.MessageBus/GlobalUsings.cs diff --git a/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs b/crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs similarity index 100% rename from Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs rename to crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs diff --git a/crs/Services/Email/Email.Templates/AssemblyReference.cs b/crs/Services/Email/Email.Templates/AssemblyReference.cs index 19b635b..9dc033d 100644 --- a/crs/Services/Email/Email.Templates/AssemblyReference.cs +++ b/crs/Services/Email/Email.Templates/AssemblyReference.cs @@ -3,4 +3,5 @@ public static class AssemblyReference { public static readonly Assembly Assembly = typeof(AssemblyReference).Assembly; + public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.Location)!; } diff --git a/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj new file mode 100644 index 0000000..fa71b7a --- /dev/null +++ b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj @@ -0,0 +1,9 @@ + + + + net8.0 + enable + enable + + + diff --git a/crs/Services/Identity/Identity.App/Configurations/InfrastructureServiceInstaller.cs b/crs/Services/Identity/Identity.App/Configurations/InfrastructureServiceInstaller.cs index 7052c08..9e8d37d 100644 --- a/crs/Services/Identity/Identity.App/Configurations/InfrastructureServiceInstaller.cs +++ b/crs/Services/Identity/Identity.App/Configurations/InfrastructureServiceInstaller.cs @@ -9,8 +9,6 @@ public void Install(IServiceCollection services, IConfiguration configuration) services.AddDbContext(options => options.UseNpgsql(Env.ConnectionStrings.POSTGRES)); - services.AddTransient(); - services.Scan(selector => selector.FromAssemblies( Infrastructure.AssemblyReference.Assembly, diff --git a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs b/crs/Services/Identity/Identity.App/Configurations/MessageBusServiceInstaller.cs similarity index 92% rename from crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs rename to crs/Services/Identity/Identity.App/Configurations/MessageBusServiceInstaller.cs index 2f1f39c..453e3d2 100644 --- a/crs/Services/Identity/Identity.App/Configurations/EventBusServiceInstaller.cs +++ b/crs/Services/Identity/Identity.App/Configurations/MessageBusServiceInstaller.cs @@ -1,6 +1,6 @@ namespace Identity.App.Configurations; -internal sealed class EventBusServiceInstaller : IServiceInstaller +internal sealed class MessageBusServiceInstaller : IServiceInstaller { public void Install(IServiceCollection services, IConfiguration configuration) { diff --git a/crs/Services/Identity/Identity.App/Startup.cs b/crs/Services/Identity/Identity.App/Startup.cs index 84683ee..35ea0ed 100644 --- a/crs/Services/Identity/Identity.App/Startup.cs +++ b/crs/Services/Identity/Identity.App/Startup.cs @@ -4,12 +4,8 @@ public sealed class Startup(IConfiguration configuration) { private readonly IConfiguration _configuration = configuration; - public void ConfigureServices(IServiceCollection services) - { - services.InstallServicesFromAssembly( - _configuration, - App.AssemblyReference.Assembly); - } + public void ConfigureServices(IServiceCollection services) => + services.InstallServicesFromAssembly(_configuration, App.AssemblyReference.Assembly); public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { @@ -18,7 +14,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(); - } + } app.UseMiddleware(); diff --git a/crs/Services/Identity/Identity.Presentation/AssemblyReference.cs b/crs/Services/Identity/Identity.Presentation/AssemblyReference.cs index b4277e6..59d689b 100644 --- a/crs/Services/Identity/Identity.Presentation/AssemblyReference.cs +++ b/crs/Services/Identity/Identity.Presentation/AssemblyReference.cs @@ -3,5 +3,4 @@ public static class AssemblyReference { public static readonly Assembly Assembly = typeof(AssemblyReference).Assembly; - public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.Location)!; } diff --git a/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs b/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs index 187c670..501c1d7 100644 --- a/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs +++ b/crs/Services/Identity/Identity.Presentation/V1/Controllers/UserController.cs @@ -76,7 +76,7 @@ public async Task ConfirmEmail([FromQuery] ConfirmEmailRequest re var command = new ConfirmEmailCommand(request.UserId, request.EmailConfirmationToken); var result = await _sender.Send(command); - return result.IsSuccess ? Redirect(request.returnUrl) + return result.IsSuccess ? Redirect(request.ReturnUrl) : HandleFailure(result); } diff --git a/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs b/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs index 5e18f0a..9f38630 100644 --- a/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs +++ b/crs/Services/Identity/Identity.Presentation/V1/Models/ConfirmEmailRequest.cs @@ -3,4 +3,4 @@ public sealed record ConfirmEmailRequest( [Required] Guid UserId, [Required] string EmailConfirmationToken, - [Required] string returnUrl); + [Required] string ReturnUrl); From 095c0e091ca135110ecb385e4ddbdfab55fdd558 Mon Sep 17 00:00:00 2001 From: Akber Date: Mon, 5 Feb 2024 20:40:33 +0400 Subject: [PATCH 7/7] Fix Grpc generate problem. Add grpc service installer in identity and email project. Add in iJwtService CreateToken method and implement in JwtService . Delete email logic in identity service and implement message pattern logic. --- crs/CommonComponents/Common/Common.csproj | 2 +- .../Contracts/Abstractions/Abstractions.proto | 4 +- .../Contracts/Contracts.csproj | 34 ++++++---- .../Services/Identity/Identity.proto | 20 +++--- .../GlobalUsings.cs | 2 - crs/Docker/.env | 8 ++- crs/Docker/docker-compose.override.yml | 8 +++ .../Catalog.Infrastructure.csproj | 2 +- .../Configurations/GrpcServiceInstaller.cs | 14 +++++ crs/Services/Email/Email.App/Email.App.csproj | 2 + crs/Services/Email/Email.App/Env.cs | 1 + crs/Services/Email/Email.App/GlobalUsings.cs | 1 + crs/Services/Email/Email.App/appsettings.yml | 8 --- ...ndConfirmationUserMessageCommandHandler.cs | 4 +- .../Email/Email.Application/GlobalUsings.cs | 2 +- .../Email.Infrastructure.csproj | 2 + .../Email/Abstractions/IEmailService.cs | 2 +- .../Email/EmailOptions.cs | 1 + .../Email/EmailTemplatePath.cs | 2 +- .../Email/Services/EmailBaseService.cs | 11 +++- .../Email/Services/IdentityEmailService.cs | 2 +- .../Email.Infrastructure/GlobalUsings.cs | 3 +- .../Email.MessageBus/Email.MessageBus.csproj | 1 + .../Email/Email.MessageBus/GlobalUsings.cs | 3 +- ...atedConfirmationEmailSendCommandHandler.cs | 23 +++++-- .../Identity/Idenitty.Grpc/GlobalUsings.cs | 3 + .../Idenitty.Grpc/Idenitty.Grpc.csproj | 21 +++++-- .../Idenitty.Grpc/IdentityGrpcService.cs | 13 ++++ .../Configurations/GrpcServiceInstaller.cs | 9 +++ .../Identity/Identity.App/GlobalUsings.cs | 2 +- .../Identity/Identity.App/Identity.App.csproj | 2 + crs/Services/Identity/Identity.App/Startup.cs | 4 +- .../Abstractions/IIdentityEmailService.cs | 7 --- .../Identity.Application/GlobalUsings.cs | 8 +-- .../Identity.Application.csproj | 7 ++- .../Register/RegisterCommandHandler.cs | 16 ++--- .../RetryConfirmEmailSendCommandHandler.cs | 21 ++++--- .../GetUserInfoById/GetUserInfoByIdHandler.cs | 6 ++ .../Authentication}/IJwtProvider.cs | 2 +- .../Email/EmailOptions.cs | 10 --- .../Email/IdentityEmailService.cs | 63 ------------------- .../Identity.Infrastructure/GlobalUsings.cs | 5 +- .../Hashing/HashingService.cs | 14 +++-- .../Hashing}/IHashingService.cs | 3 +- .../Identity.Infrastructure.csproj | 5 +- 45 files changed, 207 insertions(+), 176 deletions(-) create mode 100644 crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs create mode 100644 crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs create mode 100644 crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs create mode 100644 crs/Services/Identity/Identity.App/Configurations/GrpcServiceInstaller.cs delete mode 100644 crs/Services/Identity/Identity.Application/Abstractions/IIdentityEmailService.cs create mode 100644 crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs rename crs/Services/Identity/{Identity.Application/Abstractions => Identity.Infrastructure/Authentication}/IJwtProvider.cs (87%) delete mode 100644 crs/Services/Identity/Identity.Infrastructure/Email/EmailOptions.cs delete mode 100644 crs/Services/Identity/Identity.Infrastructure/Email/IdentityEmailService.cs rename crs/Services/Identity/{Identity.Application/Abstractions => Identity.Infrastructure/Hashing}/IHashingService.cs (69%) diff --git a/crs/CommonComponents/Common/Common.csproj b/crs/CommonComponents/Common/Common.csproj index 31d3ec4..7e899d2 100644 --- a/crs/CommonComponents/Common/Common.csproj +++ b/crs/CommonComponents/Common/Common.csproj @@ -16,7 +16,7 @@ - + diff --git a/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto index 73d6be8..435bafb 100644 --- a/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto +++ b/crs/CommonComponents/Contracts/Abstractions/Abstractions.proto @@ -1,6 +1,8 @@ syntax = "proto3"; -package Contracts.Abstractions.Protobuf; +option csharp_namespace = "Contracts.Abstractions"; + +package abstractions; message NotFound {} diff --git a/crs/CommonComponents/Contracts/Contracts.csproj b/crs/CommonComponents/Contracts/Contracts.csproj index b20aba8..7521ead 100644 --- a/crs/CommonComponents/Contracts/Contracts.csproj +++ b/crs/CommonComponents/Contracts/Contracts.csproj @@ -1,18 +1,28 @@  - - net8.0 - enable - enable - + + net8.0 + enable + enable + - - - - + + + + - - - + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto index 41bc837..2be51d9 100644 --- a/crs/CommonComponents/Contracts/Services/Identity/Identity.proto +++ b/crs/CommonComponents/Contracts/Services/Identity/Identity.proto @@ -1,10 +1,10 @@ syntax = "proto3"; -package Contracts.Services.Idenitty.Protobuf; +option csharp_namespace = "Contracts.Services.Identity"; -import "Abstractions/Abstractions.proto"; +package identity; -service IdenittyService { +service IdentityService { rpc GetUser(GetUserRequest) returns (User); } @@ -12,14 +12,14 @@ message GetUserRequest { string id = 1; } -message UserDetails { +message User { string user_id = 1; - string email = 3; - string first_name = 2; - string last_name = 2; - bool is_email_confirmed = 4; - Role role = 5; - Gender gender = 6; + string email = 2; + string first_name = 3; + string last_name = 4; + bool is_email_confirmed = 5; + Role role = 6; + Gender gender = 7; } enum Role { diff --git a/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/GlobalUsings.cs b/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/GlobalUsings.cs index b98ca87..b363e81 100644 --- a/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/GlobalUsings.cs +++ b/crs/CommonComponents/EventBus/EventBus.MassTransit.RabbitMQ/GlobalUsings.cs @@ -1,4 +1,2 @@ global using MassTransit; -global using MassTransit.Configuration; global using EventBus.Common.Abstractions; -global using Common.Events; diff --git a/crs/Docker/.env b/crs/Docker/.env index 5c5e38b..a9a4364 100644 --- a/crs/Docker/.env +++ b/crs/Docker/.env @@ -19,4 +19,10 @@ REDIS_PASSWORD=Password123 RABBITMQ_DEFAULT_USER=admin RABBITMQ_DEFAULT_PASS=admin -CERTBOT_EMAIL=akber.sharifov2004@gmail.com \ No newline at end of file +CERTBOT_EMAIL=akber.sharifov2004@gmail.com + +EMAIL_FROM=Eshop +EMAIL_HOST=smtp.gmail.com +EMAIL_PORT=587 +EMAIL_USERNAME=akber.sharifov2004@gmail.com +EMAIL_PASSWORD=ueey qfia bnyx atce diff --git a/crs/Docker/docker-compose.override.yml b/crs/Docker/docker-compose.override.yml index ab93911..9884f16 100644 --- a/crs/Docker/docker-compose.override.yml +++ b/crs/Docker/docker-compose.override.yml @@ -80,11 +80,19 @@ services: - ASPNETCORE_HTTP_PORTS=5110 - ASPNETCORE_ENVIRONMENT=Development # Custom environment variables + - Email__From=${EMAIL_FROM}} + - Email__Host=${EMAIL_HOST} + - Email__Port=${EMAIL_PORT} + - Email__Username=${EMAIL_USERNAME} + - Email__Password=${EMAIL_PASSWORD} + - Retry__Message__Send__Count=3 - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER} - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS} ports: - "5110:80" + + mssql: environment: - ACCEPT_EULA=Y diff --git a/crs/Services/Catalog/Catalog.Infrastructure/Catalog.Infrastructure.csproj b/crs/Services/Catalog/Catalog.Infrastructure/Catalog.Infrastructure.csproj index b0f378e..61ea681 100644 --- a/crs/Services/Catalog/Catalog.Infrastructure/Catalog.Infrastructure.csproj +++ b/crs/Services/Catalog/Catalog.Infrastructure/Catalog.Infrastructure.csproj @@ -8,7 +8,7 @@ - + diff --git a/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs b/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs new file mode 100644 index 0000000..1dbe857 --- /dev/null +++ b/crs/Services/Email/Email.App/Configurations/GrpcServiceInstaller.cs @@ -0,0 +1,14 @@ +namespace Email.App.Configurations; + +internal sealed class GrpcServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.AddGrpcClient(options => + { + options.Address = new Uri(Env.IDENTITY_URL); + }); + + services.AddGrpc(); + } +} diff --git a/crs/Services/Email/Email.App/Email.App.csproj b/crs/Services/Email/Email.App/Email.App.csproj index 0f52a74..09640ab 100644 --- a/crs/Services/Email/Email.App/Email.App.csproj +++ b/crs/Services/Email/Email.App/Email.App.csproj @@ -12,6 +12,7 @@ + @@ -24,6 +25,7 @@ + diff --git a/crs/Services/Email/Email.App/Env.cs b/crs/Services/Email/Email.App/Env.cs index 9709874..093443a 100644 --- a/crs/Services/Email/Email.App/Env.cs +++ b/crs/Services/Email/Email.App/Env.cs @@ -5,6 +5,7 @@ ///
internal static class Env { + public static string IDENTITY_URL => GetEnvironmentVariable("IDENTITY_URL"); public static string RABBITMQ_DEFAULT_USER => GetEnvironmentVariable("RABBITMQ_DEFAULT_USER"); public static string RABBITMQ_DEFAULT_PASS => GetEnvironmentVariable("RABBITMQ_DEFAULT_PASS"); diff --git a/crs/Services/Email/Email.App/GlobalUsings.cs b/crs/Services/Email/Email.App/GlobalUsings.cs index 55dfe3a..22f1a83 100644 --- a/crs/Services/Email/Email.App/GlobalUsings.cs +++ b/crs/Services/Email/Email.App/GlobalUsings.cs @@ -8,3 +8,4 @@ global using FluentValidation; global using Email.App.OptionsSetup; global using Common.Infrastructure.Middleware; +global using Contracts.Services.Identity; \ No newline at end of file diff --git a/crs/Services/Email/Email.App/appsettings.yml b/crs/Services/Email/Email.App/appsettings.yml index a113568..cda87cf 100644 --- a/crs/Services/Email/Email.App/appsettings.yml +++ b/crs/Services/Email/Email.App/appsettings.yml @@ -2,14 +2,6 @@ Logging: LogLevel: Default: Information Microsoft.AspNetCore: Warning - -Email: - From: Eshop - Host: smtp.gmail.com - Port: 587 - Username: akber.sharifov2004@gmail.com - Password: ueey qfia bnyx atce - Swagger: Title: "Email API" diff --git a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs index 416c904..907b2e2 100644 --- a/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs +++ b/crs/Services/Email/Email.Application/Emails/Commands/SendConfirmationUserMessage/SendConfirmationUserMessageCommandHandler.cs @@ -4,11 +4,13 @@ internal sealed class SendConfirmationUserMessageCommandHandler(IIdentityEmailSe : ICommandHandler { private readonly IIdentityEmailService _emailService = emailService; - private readonly I public Task Handle(SendConfirmationUserMessageCommand request, CancellationToken cancellationToken) { + + + _emailService.SendConfirmationEmailAsync( new SendConfirmationEmailRequest { diff --git a/crs/Services/Email/Email.Application/GlobalUsings.cs b/crs/Services/Email/Email.Application/GlobalUsings.cs index b40ad76..1fb9d34 100644 --- a/crs/Services/Email/Email.Application/GlobalUsings.cs +++ b/crs/Services/Email/Email.Application/GlobalUsings.cs @@ -1,4 +1,4 @@ global using System.Reflection; global using Common.Application.Abstractions.Messaging.Command; global using Common.Domain.Primitives.Results; -global using Email.Infrastructure.Email.Abstractions; \ No newline at end of file +global using Email.Infrastructure.Email.Abstractions; diff --git a/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj b/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj index 4ab33d7..02e8703 100644 --- a/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj +++ b/crs/Services/Email/Email.Infrastructure/Email.Infrastructure.csproj @@ -10,6 +10,8 @@ + + diff --git a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs index a6a6941..b465a03 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Abstractions/IEmailService.cs @@ -8,5 +8,5 @@ public interface IEmailService /// The . /// The . /// - Task SendAsync(SendMessageRequest request, CancellationToken cancellationToken = default); + Task SendMessageAsync(SendMessageRequest request, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/crs/Services/Email/Email.Infrastructure/Email/EmailOptions.cs b/crs/Services/Email/Email.Infrastructure/Email/EmailOptions.cs index 3113fdd..46007c9 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/EmailOptions.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/EmailOptions.cs @@ -7,4 +7,5 @@ public class EmailOptions public int Port { get; set; } public string Username { get; set; } = null!; public string Password { get; set; } = null!; + public int RetryMessageSendCount { get; set; } } diff --git a/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs b/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs index c19ecc4..1d3112f 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/EmailTemplatePath.cs @@ -3,7 +3,7 @@ /// /// This class is used to get the path of the email templates. /// -public static class EmailTemplatePath +internal static class EmailTemplatePath { /// /// required change this template: {{firstName}}, {{lastName}}, {{confirmationLink}} diff --git a/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs b/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs index 303d4ca..ae859f5 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Services/EmailBaseService.cs @@ -1,10 +1,17 @@ namespace Email.Infrastructure.Email; -public abstract class EmailBaseService(IOptions options) : IEmailService +internal abstract class EmailBaseService(IOptions options) : IEmailService { private readonly EmailOptions _options = options.Value; - public async Task SendAsync(SendMessageRequest request, CancellationToken cancellationToken = default) + public async Task SendMessageAsync(SendMessageRequest request, CancellationToken cancellationToken = default) => + await Policy.Handle() + .WaitAndRetryAsync( + _options.RetryMessageSendCount, + retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))) + .ExecuteAsync(async () => await SendAsync(request, cancellationToken)); + + private async Task SendAsync(SendMessageRequest request, CancellationToken cancellationToken = default) { MimeMessage message = new(); message.From.Add(MailboxAddress.Parse(_options.From)); diff --git a/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs index caeaf77..3f4798f 100644 --- a/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs +++ b/crs/Services/Email/Email.Infrastructure/Email/Services/IdentityEmailService.cs @@ -29,6 +29,6 @@ public async Task SendConfirmationEmailAsync(SendConfirmationEmailRequest reques Body: confirmEmailTemplate ); - await SendAsync(sendMessageRequest, cancellationToken); + await SendMessageAsync(sendMessageRequest, cancellationToken); } } diff --git a/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs b/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs index 17abbbd..cf8002c 100644 --- a/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs +++ b/crs/Services/Email/Email.Infrastructure/GlobalUsings.cs @@ -5,4 +5,5 @@ global using MimeKit; global using MailKit.Net.Smtp; global using System.Reflection; -global using System.Text.Encodings.Web; \ No newline at end of file +global using System.Text.Encodings.Web; +global using Polly; \ No newline at end of file diff --git a/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj b/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj index 8b77fed..bb79e2e 100644 --- a/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj +++ b/crs/Services/Email/Email.MessageBus/Email.MessageBus.csproj @@ -13,6 +13,7 @@ + diff --git a/crs/Services/Email/Email.MessageBus/GlobalUsings.cs b/crs/Services/Email/Email.MessageBus/GlobalUsings.cs index 5b4d468..23ec1f6 100644 --- a/crs/Services/Email/Email.MessageBus/GlobalUsings.cs +++ b/crs/Services/Email/Email.MessageBus/GlobalUsings.cs @@ -1,3 +1,4 @@ global using EventBus.MassTransit.Handlers; global using Contracts.Services.Identity.Commands; -global using MassTransit; \ No newline at end of file +global using MassTransit; +global using MediatR; diff --git a/crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs b/crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs index fdd1746..1279647 100644 --- a/crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs +++ b/crs/Services/Email/Email.MessageBus/Handlers/Commands/UserCreatedConfirmationEmailSendCommandHandler.cs @@ -1,10 +1,23 @@ -namespace Email.MessageBus.Handlers.Commands; +using Email.Application.Emails.Commands.SendConfirmationUserMessage; -public sealed class UserCreatedConfirmationEmailSendCommandHandler - : IntegrationCommandHandler +namespace Email.MessageBus.Handlers.Commands; + +internal sealed class UserCreatedConfirmationEmailSendCommandHandler(ISender sender) + : IntegrationCommandHandler { - public override Task Handle(ConsumeContext context) + private readonly ISender _sender = sender; + + public override async Task Handle(ConsumeContext context) { - throw new NotImplementedException(); + var request = new SendConfirmationUserMessageCommand( + context.Message.UserId, + context.Message.ReturnUrl); + + var result = await _sender.Send(request); + + if (result.IsFailure) + { + throw new Exception(result.Error); + } } } diff --git a/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs b/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs new file mode 100644 index 0000000..854cfaa --- /dev/null +++ b/crs/Services/Identity/Idenitty.Grpc/GlobalUsings.cs @@ -0,0 +1,3 @@ +global using Grpc.Core; +global using Contracts.Services.Identity; +global using MediatR; \ No newline at end of file diff --git a/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj index fa71b7a..df18c01 100644 --- a/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj +++ b/crs/Services/Identity/Idenitty.Grpc/Idenitty.Grpc.csproj @@ -1,9 +1,20 @@  - - net8.0 - enable - enable - + + net8.0 + enable + enable + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs b/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs new file mode 100644 index 0000000..809728a --- /dev/null +++ b/crs/Services/Identity/Idenitty.Grpc/IdentityGrpcService.cs @@ -0,0 +1,13 @@ +namespace Idenitty.Grpc; + +public sealed class IdentityGrpcService(ISender sender) : IdentityService.IdentityServiceBase +{ + private readonly ISender _sender = sender; + + public override async Task GetUser(GetUserRequest request, ServerCallContext context) + { + var result = await _sender.Send(); + + return base.GetUser(request, context); + } +} diff --git a/crs/Services/Identity/Identity.App/Configurations/GrpcServiceInstaller.cs b/crs/Services/Identity/Identity.App/Configurations/GrpcServiceInstaller.cs new file mode 100644 index 0000000..fe8fe97 --- /dev/null +++ b/crs/Services/Identity/Identity.App/Configurations/GrpcServiceInstaller.cs @@ -0,0 +1,9 @@ +namespace Identity.App.Configurations; + +internal sealed class GrpcServiceInstaller : IServiceInstaller +{ + public void Install(IServiceCollection services, IConfiguration configuration) + { + services.AddGrpc(); + } +} diff --git a/crs/Services/Identity/Identity.App/GlobalUsings.cs b/crs/Services/Identity/Identity.App/GlobalUsings.cs index 892b07e..ba5abeb 100644 --- a/crs/Services/Identity/Identity.App/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.App/GlobalUsings.cs @@ -3,7 +3,6 @@ global using Identity.App.OptionsSetup; global using Identity.Infrastructure.Authentication; global using Identity.Infrastructure.BackgroundJobs; -global using Identity.Infrastructure.Email; global using Identity.Infrastructure.Idempotence; global using Identity.Persistence; global using MediatR; @@ -29,3 +28,4 @@ global using MassTransit; global using EventBus.Common.Abstractions; global using EventBus.MassTransit.RabbitMQ.Services; +global using Idenitty.Grpc; diff --git a/crs/Services/Identity/Identity.App/Identity.App.csproj b/crs/Services/Identity/Identity.App/Identity.App.csproj index e1dd84e..5252d13 100644 --- a/crs/Services/Identity/Identity.App/Identity.App.csproj +++ b/crs/Services/Identity/Identity.App/Identity.App.csproj @@ -17,6 +17,7 @@ + @@ -46,6 +47,7 @@ + diff --git a/crs/Services/Identity/Identity.App/Startup.cs b/crs/Services/Identity/Identity.App/Startup.cs index 35ea0ed..88775bb 100644 --- a/crs/Services/Identity/Identity.App/Startup.cs +++ b/crs/Services/Identity/Identity.App/Startup.cs @@ -14,7 +14,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(); - } + } app.UseMiddleware(); @@ -31,11 +31,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { configure.MapControllers(); configure.MapPrometheusScrapingEndpoint(); + configure.MapGrpcService(); configure.MapHealthChecks("/health", new HealthCheckOptions { ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse }); }); } - } diff --git a/crs/Services/Identity/Identity.Application/Abstractions/IIdentityEmailService.cs b/crs/Services/Identity/Identity.Application/Abstractions/IIdentityEmailService.cs deleted file mode 100644 index abad712..0000000 --- a/crs/Services/Identity/Identity.Application/Abstractions/IIdentityEmailService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Identity.Application.Abstractions; - -public interface IIdentityEmailService : IEmailService -{ - Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnUrl, CancellationToken cancellationToken = default); - EmailConfirmationToken CreateConfirmationEmailToken(); -} diff --git a/crs/Services/Identity/Identity.Application/GlobalUsings.cs b/crs/Services/Identity/Identity.Application/GlobalUsings.cs index 70d491c..88f94f1 100644 --- a/crs/Services/Identity/Identity.Application/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.Application/GlobalUsings.cs @@ -1,18 +1,18 @@ global using Common.Application.Abstractions.Messaging.Query; -global using Identity.Application.Abstractions; global using Identity.Domain.UserAggregate; global using Identity.Domain.UserAggregate.DomainEvents; global using Identity.Domain.UserAggregate.Errors; global using Identity.Domain.UserAggregate.Repositories; global using Identity.Domain.UserAggregate.ValueObjects; global using Identity.Domain.UserAggregate.Ids; -global using Common.Application.Abstractions; global using Common.Application.Abstractions.Messaging.Command; global using Common.Domain.Primitives; global using Common.Domain.Primitives.Events; global using Common.Domain.Primitives.Results; global using FluentValidation; global using System.Reflection; -global using System.Security.Claims; global using Contracts.Enumurations; -global using EventBus.Common.Abstractions; \ No newline at end of file +global using EventBus.Common.Abstractions; +global using Contracts.Services.Identity.Commands; +global using Identity.Infrastructure.Hashing; +global using Identity.Infrastructure.Authentication; \ No newline at end of file diff --git a/crs/Services/Identity/Identity.Application/Identity.Application.csproj b/crs/Services/Identity/Identity.Application/Identity.Application.csproj index 3d84051..7ef1778 100644 --- a/crs/Services/Identity/Identity.Application/Identity.Application.csproj +++ b/crs/Services/Identity/Identity.Application/Identity.Application.csproj @@ -10,10 +10,15 @@ + - + + + + + diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs index e82a77a..5940757 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/Register/RegisterCommandHandler.cs @@ -1,20 +1,16 @@ -using Contracts.Services.Identity.Commands; - -namespace Identity.Application.Users.Commands.Register; +namespace Identity.Application.Users.Commands.Register; internal sealed class RegisterCommandHandler( IHashingService hashingService, - IIdentityEmailService emailService, IUserRepository userRepository, IUnitOfWork unitOfWork, - IMessageBus eventBus) + IMessageBus messageBus) : ICommandHandler { private readonly IHashingService _hashingService = hashingService; - private readonly IIdentityEmailService _emailService = emailService; private readonly IUserRepository _userRepository = userRepository; private readonly IUnitOfWork _unitOfWork = unitOfWork; - private readonly IMessageBus _eventBus = eventBus; + private readonly IMessageBus _messageBus = messageBus; public async Task Handle(RegisterCommand request, CancellationToken cancellationToken) @@ -31,8 +27,8 @@ public async Task Handle(RegisterCommand request, CancellationToken canc await _userRepository.AddUserAsync(user, cancellationToken); await _unitOfWork.SaveChangesAsync(cancellationToken); - await _eventBus.Send( - new UserCreatedConfirmationEmailSendCommand(Guid.NewGuid(), user.Id.Value, user.EmailConfirmationToken, request.ReturnUrl), + await _messageBus.Send( + new UserCreatedConfirmationEmailSendCommand(Guid.NewGuid(), user.Id.Value, user.EmailConfirmationToken.Value, request.ReturnUrl), cancellationToken); return Result.Success(); @@ -53,7 +49,7 @@ private async Task> CreateUserResultAsync( var hash = _hashingService.Hash(request.Password, generateSalt); var passwordHashResult = PasswordHash.Create(hash); - var emailConfirmationToken = _emailService.CreateConfirmationEmailToken(); + var emailConfirmationToken = _hashingService.GenerateToken(); var role = Role.FromName(request.Role); var gender = Gender.FromName(request.Gender); diff --git a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs index 2f3d78d..8ee1e2f 100644 --- a/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs +++ b/crs/Services/Identity/Identity.Application/Users/Commands/RetryConfirmEmailSend/RetryConfirmEmailSendCommandHandler.cs @@ -1,12 +1,14 @@ namespace Identity.Application.Users.Commands.RetryConfirmEmailSend; public class RetryConfirmEmailSendCommandHandler( - IUserRepository userRepository, - IIdentityEmailService emailService) + IUserRepository userRepository, + IMessageBus messageBus, + IHashingService hashingService) : ICommandHandler { private readonly IUserRepository _userRepository = userRepository; - private readonly IIdentityEmailService _emailService = emailService; + private readonly IHashingService _hashingService = hashingService; + private readonly IMessageBus _messageBus = messageBus; public async Task Handle(RetryConfirmEmailSendCommand request, CancellationToken cancellationToken) { @@ -20,7 +22,7 @@ public async Task Handle(RetryConfirmEmailSendCommand request, Cancellat UserErrors.UserDoesNotExist); } - var confirmationEmailToken = _emailService.CreateConfirmationEmailToken(); + var confirmationEmailToken = _hashingService.GenerateToken(); var RetryEmailConfirmationResult = user.RetryEmailConfirmation(confirmationEmailToken); @@ -31,11 +33,12 @@ public async Task Handle(RetryConfirmEmailSendCommand request, Cancellat RetryEmailConfirmationResult.Error); } - //await _emailService.SendConfirmationEmailAsync( - // user, - // request.EmailConfirmPagePath, - // request.ReturnUrl, - // cancellationToken); + await _messageBus.Send(new UserCreatedConfirmationEmailSendCommand( + Guid.NewGuid(), + user.Id.Value, + confirmationEmailToken, + request.ReturnUrl), + cancellationToken); return Result.Success(); } diff --git a/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs new file mode 100644 index 0000000..6ea1114 --- /dev/null +++ b/crs/Services/Identity/Identity.Application/Users/Queries/GetUserInfoById/GetUserInfoByIdHandler.cs @@ -0,0 +1,6 @@ +namespace Identity.Application.Users.Queries.GetUserInfoById; + +internal sealed class GetUserInfoByIdHandler +{ + +} \ No newline at end of file diff --git a/crs/Services/Identity/Identity.Application/Abstractions/IJwtProvider.cs b/crs/Services/Identity/Identity.Infrastructure/Authentication/IJwtProvider.cs similarity index 87% rename from crs/Services/Identity/Identity.Application/Abstractions/IJwtProvider.cs rename to crs/Services/Identity/Identity.Infrastructure/Authentication/IJwtProvider.cs index 248aff3..e546d79 100644 --- a/crs/Services/Identity/Identity.Application/Abstractions/IJwtProvider.cs +++ b/crs/Services/Identity/Identity.Infrastructure/Authentication/IJwtProvider.cs @@ -1,4 +1,4 @@ -namespace Identity.Application.Abstractions; +namespace Identity.Infrastructure.Authentication; public interface IJwtProvider { diff --git a/crs/Services/Identity/Identity.Infrastructure/Email/EmailOptions.cs b/crs/Services/Identity/Identity.Infrastructure/Email/EmailOptions.cs deleted file mode 100644 index 594d8c0..0000000 --- a/crs/Services/Identity/Identity.Infrastructure/Email/EmailOptions.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Identity.Infrastructure.Email; - -public class EmailOptions -{ - public string From { get; set; } = null!; - public string Host { get; set; } = null!; - public int Port { get; set; } - public string Username { get; set; } = null!; - public string Password { get; set; } = null!; -} diff --git a/crs/Services/Identity/Identity.Infrastructure/Email/IdentityEmailService.cs b/crs/Services/Identity/Identity.Infrastructure/Email/IdentityEmailService.cs deleted file mode 100644 index 3202f44..0000000 --- a/crs/Services/Identity/Identity.Infrastructure/Email/IdentityEmailService.cs +++ /dev/null @@ -1,63 +0,0 @@ -using MimeKit; -using MailKit.Security; -using System.Text.Encodings.Web; - -namespace Identity.Infrastructure.Email; - -public sealed class IdentityEmailService( - IOptions emailOptions) : IIdentityEmailService -{ - private readonly EmailOptions _emailOptions = emailOptions.Value; - - public EmailConfirmationToken CreateConfirmationEmailToken() - { - var CreateConfirmationEmailTokenString = Guid.NewGuid().ToString(); - return EmailConfirmationToken.Create(CreateConfirmationEmailTokenString).Value; - } - - public async Task SendAsync(string to, string subject, string body, CancellationToken cancellationToken = default) - { - MimeMessage message = new(); - message.From.Add(MailboxAddress.Parse(_emailOptions.From)); - message.To.Add(MailboxAddress.Parse(to)); - message.Subject = subject; - message.Body = new TextPart(MimeKit.Text.TextFormat.Html) { Text = body }; - - using SmtpClient client = new(); - - await client.ConnectAsync( - _emailOptions.Host, - _emailOptions.Port, - SecureSocketOptions.Auto, - cancellationToken); - - await client.AuthenticateAsync( - _emailOptions.Username, - _emailOptions.Password, - cancellationToken); - - await client.SendAsync(message, cancellationToken); - await client.DisconnectAsync(true, cancellationToken); - } - - public async Task SendConfirmationEmailAsync(User user, string emailConfirmPagePath, string returnPath, CancellationToken cancellationToken = default) - { - var subject = $"Confirm your email {user.FirstName.Value} {user.LastName.Value}"; - - string confirmEmailTemplate = - await File.ReadAllTextAsync(emailConfirmPagePath, cancellationToken); - - var confirmUrl = - $@"{returnPath}?UserId={user.Id.Value}&EmailConfirmationToken={user.EmailConfirmationToken.Value}"; - - var confirmUrlEncode = HtmlEncoder.Default.Encode(confirmUrl); - - var body = - confirmEmailTemplate - .Replace("{{confirmationLink}}", confirmUrlEncode) - .Replace("{{firstName}}", user.FirstName.Value) - .Replace("{{lastName}}", user.LastName.Value); - - await SendAsync(user.Email.Value, subject, body, cancellationToken); - } -} diff --git a/crs/Services/Identity/Identity.Infrastructure/GlobalUsings.cs b/crs/Services/Identity/Identity.Infrastructure/GlobalUsings.cs index 6206638..e1f041d 100644 --- a/crs/Services/Identity/Identity.Infrastructure/GlobalUsings.cs +++ b/crs/Services/Identity/Identity.Infrastructure/GlobalUsings.cs @@ -1,7 +1,5 @@ -global using Identity.Application.Abstractions; -global using Identity.Domain.UserAggregate; +global using Identity.Domain.UserAggregate; global using Identity.Persistence; -global using MailKit.Net.Smtp; global using MediatR; global using Microsoft.AspNetCore.Identity.EntityFrameworkCore; global using Microsoft.EntityFrameworkCore; @@ -14,3 +12,4 @@ global using System.Text; global using Microsoft.Extensions.Options; global using Identity.Domain.UserAggregate.ValueObjects; +global using System.Security.Claims; diff --git a/crs/Services/Identity/Identity.Infrastructure/Hashing/HashingService.cs b/crs/Services/Identity/Identity.Infrastructure/Hashing/HashingService.cs index d4bc669..4b9cf1b 100644 --- a/crs/Services/Identity/Identity.Infrastructure/Hashing/HashingService.cs +++ b/crs/Services/Identity/Identity.Infrastructure/Hashing/HashingService.cs @@ -4,12 +4,7 @@ namespace Identity.Infrastructure.Hashing; public class HashingService : IHashingService { - public string GenerateSalt() - { - using var hmac = new HMACSHA256(); - var salt = ConvertToString(hmac.Key); - return salt; - } + public string GenerateSalt() => GenerateToken(); public string Hash(string password, string salt) { @@ -32,4 +27,11 @@ private static byte[] ConvertToBytes(string value) => private static string ConvertToString(byte[] value) => Convert.ToBase64String(value); + + public string GenerateToken() + { + using var hmac = new HMACSHA256(); + var token = ConvertToString(hmac.Key); + return token; + } } diff --git a/crs/Services/Identity/Identity.Application/Abstractions/IHashingService.cs b/crs/Services/Identity/Identity.Infrastructure/Hashing/IHashingService.cs similarity index 69% rename from crs/Services/Identity/Identity.Application/Abstractions/IHashingService.cs rename to crs/Services/Identity/Identity.Infrastructure/Hashing/IHashingService.cs index 96725b8..56feff9 100644 --- a/crs/Services/Identity/Identity.Application/Abstractions/IHashingService.cs +++ b/crs/Services/Identity/Identity.Infrastructure/Hashing/IHashingService.cs @@ -1,8 +1,9 @@ -namespace Identity.Application.Abstractions; +namespace Identity.Infrastructure.Hashing; public interface IHashingService { string Hash(string password, string salt); bool Verify(string password, string salt, string hash); string GenerateSalt(); + string GenerateToken(); } diff --git a/crs/Services/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj b/crs/Services/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj index 3270318..b09fc69 100644 --- a/crs/Services/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj +++ b/crs/Services/Identity/Identity.Infrastructure/Identity.Infrastructure.csproj @@ -9,14 +9,13 @@ - + - + -