mirror of
https://github.com/meysamhadeli/booking-microservices.git
synced 2026-04-15 13:51:09 +08:00
refactor all properties and dtos
This commit is contained in:
parent
1168fd7bbd
commit
acb618a6fd
12
booking.rest
12
booking.rest
@ -39,13 +39,13 @@ Content-Type: application/json
|
||||
authorization: bearer {{Authenticate.response.body.access_token}}
|
||||
|
||||
{
|
||||
"firstName": "4John",
|
||||
"lastName": "4Do",
|
||||
"username": "4admin",
|
||||
"firstName": "John",
|
||||
"lastName": "Do",
|
||||
"username": "admin",
|
||||
"passportNumber": "412900000000",
|
||||
"email": "4admin@admin.com",
|
||||
"password": "4Admin@12345",
|
||||
"confirmPassword": "4Admin@12345"
|
||||
"email": "admin@admin.com",
|
||||
"password": "Admin@12345",
|
||||
"confirmPassword": "Admin@12345"
|
||||
}
|
||||
###
|
||||
|
||||
|
||||
@ -8,28 +8,25 @@ public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
|
||||
where TRequest : notnull, IRequest<TResponse>
|
||||
where TResponse : notnull
|
||||
{
|
||||
private readonly ICacheRequest _cacheRequest;
|
||||
private readonly IEasyCachingProvider _cachingProvider;
|
||||
private readonly ILogger<CachingBehavior<TRequest, TResponse>> _logger;
|
||||
private readonly int defaultCacheExpirationInHours = 1;
|
||||
|
||||
public CachingBehavior(IEasyCachingProviderFactory cachingFactory,
|
||||
ILogger<CachingBehavior<TRequest, TResponse>> logger,
|
||||
ICacheRequest cacheRequest)
|
||||
ILogger<CachingBehavior<TRequest, TResponse>> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_cachingProvider = cachingFactory.GetCachingProvider("mem");
|
||||
_cacheRequest = cacheRequest;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (request is not ICacheRequest || _cacheRequest == null)
|
||||
if (request is not ICacheRequest cacheRequest)
|
||||
// No cache request found, so just continue through the pipeline
|
||||
return await next();
|
||||
|
||||
var cacheKey = _cacheRequest.CacheKey;
|
||||
var cacheKey = cacheRequest.CacheKey;
|
||||
var cachedResponse = await _cachingProvider.GetAsync<TResponse>(cacheKey);
|
||||
if (cachedResponse.Value != null)
|
||||
{
|
||||
@ -40,7 +37,7 @@ public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
|
||||
|
||||
var response = await next();
|
||||
|
||||
var expirationTime = _cacheRequest.AbsoluteExpirationRelativeToNow ??
|
||||
var expirationTime = cacheRequest.AbsoluteExpirationRelativeToNow ??
|
||||
DateTime.Now.AddHours(defaultCacheExpirationInHours);
|
||||
|
||||
await _cachingProvider.SetAsync(cacheKey, response, expirationTime.TimeOfDay);
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace BuildingBlocks.Caching;
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IServiceCollection AddCachingRequest(this IServiceCollection services,
|
||||
IList<Assembly> assembliesToScan, ServiceLifetime lifetime = ServiceLifetime.Transient)
|
||||
{
|
||||
// ICacheRequest discovery and registration
|
||||
services.Scan(scan => scan
|
||||
.FromAssemblies(assembliesToScan ?? AppDomain.CurrentDomain.GetAssemblies())
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(ICacheRequest)),
|
||||
false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithLifetime(lifetime));
|
||||
|
||||
// IInvalidateCacheRequest discovery and registration
|
||||
services.Scan(scan => scan
|
||||
.FromAssemblies(assembliesToScan ?? AppDomain.CurrentDomain.GetAssemblies())
|
||||
.AddClasses(classes => classes.AssignableTo(typeof(IInvalidateCacheRequest)),
|
||||
false)
|
||||
.AsImplementedInterfaces()
|
||||
.WithLifetime(lifetime));
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,3 @@
|
||||
using MediatR;
|
||||
|
||||
namespace BuildingBlocks.Caching;
|
||||
|
||||
public interface ICacheRequest
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MediatR;
|
||||
|
||||
namespace BuildingBlocks.Caching
|
||||
{
|
||||
public interface IInvalidateCacheRequest
|
||||
|
||||
@ -10,27 +10,23 @@ namespace BuildingBlocks.Caching
|
||||
{
|
||||
private readonly ILogger<InvalidateCachingBehavior<TRequest, TResponse>> _logger;
|
||||
private readonly IEasyCachingProvider _cachingProvider;
|
||||
private readonly IInvalidateCacheRequest _invalidateCacheRequest;
|
||||
|
||||
|
||||
public InvalidateCachingBehavior(IEasyCachingProviderFactory cachingFactory,
|
||||
ILogger<InvalidateCachingBehavior<TRequest, TResponse>> logger,
|
||||
IInvalidateCacheRequest invalidateCacheRequest)
|
||||
ILogger<InvalidateCachingBehavior<TRequest, TResponse>> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_cachingProvider = cachingFactory.GetCachingProvider("mem");
|
||||
_invalidateCacheRequest = invalidateCacheRequest;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
if (request is not IInvalidateCacheRequest || _invalidateCacheRequest == null)
|
||||
if (request is not IInvalidateCacheRequest invalidateCacheRequest)
|
||||
{
|
||||
// No cache request found, so just continue through the pipeline
|
||||
return await next();
|
||||
}
|
||||
|
||||
var cacheKey = _invalidateCacheRequest.CacheKey;
|
||||
var cacheKey = invalidateCacheRequest.CacheKey;
|
||||
var response = await next();
|
||||
|
||||
await _cachingProvider.RemoveAsync(cacheKey);
|
||||
|
||||
@ -3,7 +3,4 @@ using BuildingBlocks.IdsGenerator;
|
||||
|
||||
namespace BuildingBlocks.Core.Event;
|
||||
|
||||
public class InternalCommand : IInternalCommand, ICommand
|
||||
{
|
||||
public long Id { get; init; } = SnowFlakIdGenerator.NewId();
|
||||
}
|
||||
public record InternalCommand : IInternalCommand, ICommand;
|
||||
|
||||
@ -27,6 +27,6 @@ namespace BuildingBlocks.Core.Model
|
||||
|
||||
public long Version { get; set; } = -1;
|
||||
|
||||
public TId Id { get; protected set; }
|
||||
public TId Id { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
using System.Data;
|
||||
using System.Text.Json;
|
||||
using BuildingBlocks.Core;
|
||||
using BuildingBlocks.Core.Event;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
||||
@ -1,25 +1,5 @@
|
||||
using Booking;
|
||||
using Booking.Data;
|
||||
using Booking.Extensions;
|
||||
using Booking.Extensions.Infrastructure;
|
||||
using BuildingBlocks.EventStoreDB;
|
||||
using BuildingBlocks.HealthCheck;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using BuildingBlocks.Jwt;
|
||||
using BuildingBlocks.Logging;
|
||||
using BuildingBlocks.Mapster;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.OpenTelemetry;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.Swagger;
|
||||
using BuildingBlocks.Web;
|
||||
using Figgle;
|
||||
using FluentValidation;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Prometheus;
|
||||
using Serilog;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
||||
@ -1,16 +1,4 @@
|
||||
namespace Booking.Booking.Dtos;
|
||||
|
||||
public record BookingResponseDto
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public string Name { get; init; }
|
||||
public string FlightNumber { get; init; }
|
||||
public long AircraftId { get; init; }
|
||||
|
||||
public decimal Price { get; init; }
|
||||
public DateTime FlightDate { get; init; }
|
||||
public string SeatNumber { get; init; }
|
||||
public long DepartureAirportId { get; init; }
|
||||
public long ArriveAirportId { get; init; }
|
||||
public string Description { get; init; }
|
||||
}
|
||||
public record BookingResponseDto(long Id, string Name, string FlightNumber, long AircraftId, decimal Price,
|
||||
DateTime FlightDate, string SeatNumber, long DepartureAirportId, long ArriveAirportId, string Description);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using Booking.Booking.Dtos;
|
||||
using Booking.Booking.Models.Reads;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Booking.Booking.Features.CreateBooking.Commands.V1;
|
||||
using Booking.Booking.Features.CreateBooking.Dtos.V1;
|
||||
using Mapster;
|
||||
|
||||
namespace Booking.Booking.Features;
|
||||
@ -12,15 +12,12 @@ public class BookingMappings : IRegister
|
||||
config.Default.NameMatchingStrategy(NameMatchingStrategy.Flexible);
|
||||
|
||||
config.NewConfig<Models.Booking, BookingResponseDto>()
|
||||
.Map(d => d.Name, s => s.PassengerInfo.Name)
|
||||
.Map(d => d.Description, s => s.Trip.Description)
|
||||
.Map(d => d.DepartureAirportId, s => s.Trip.DepartureAirportId)
|
||||
.Map(d => d.ArriveAirportId, s => s.Trip.ArriveAirportId)
|
||||
.Map(d => d.FlightNumber, s => s.Trip.FlightNumber)
|
||||
.Map(d => d.FlightDate, s => s.Trip.FlightDate)
|
||||
.Map(d => d.Price, s => s.Trip.Price)
|
||||
.Map(d => d.SeatNumber, s => s.Trip.SeatNumber)
|
||||
.Map(d => d.AircraftId, s => s.Trip.AircraftId);
|
||||
.ConstructUsing(x => new BookingResponseDto(x.Id, x.PassengerInfo.Name, x.Trip.FlightNumber,
|
||||
x.Trip.AircraftId, x.Trip.Price, x.Trip.FlightDate, x.Trip.SeatNumber, x.Trip.DepartureAirportId, x.Trip.ArriveAirportId,
|
||||
x.Trip.Description));
|
||||
|
||||
|
||||
config.NewConfig<CreateBookingRequestDto, CreateBookingCommand>()
|
||||
.ConstructUsing(x => new CreateBookingCommand(x.PassengerId, x.FlightId, x.Description));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Booking.Booking.Features.CreateBooking.Dtos.V1;
|
||||
|
||||
public record CreateBookingRequestDto(long PassengerId, long FlightId, string Description);
|
||||
@ -1,5 +1,7 @@
|
||||
using Booking.Booking.Features.CreateBooking.Commands.V1;
|
||||
using Booking.Booking.Features.CreateBooking.Dtos.V1;
|
||||
using BuildingBlocks.Web;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
@ -9,6 +11,7 @@ using Microsoft.AspNetCore.Routing;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Booking.Booking.Features.CreateBooking.Endpoints.V1;
|
||||
|
||||
public class CreateBookingEndpoint : IMinimalEndpoint
|
||||
{
|
||||
public IEndpointRouteBuilder MapEndpoint(IEndpointRouteBuilder endpoints)
|
||||
@ -27,8 +30,11 @@ public class CreateBookingEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CreateBooking(CreateBookingCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CreateBooking(CreateBookingRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CreateBookingCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
using Booking.Booking.Features.CreateBooking.Events.Domain.V1;
|
||||
using Booking.Booking.Models.ValueObjects;
|
||||
using BuildingBlocks.EventStoreDB.Events;
|
||||
using BuildingBlocks.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Booking.Booking.Models;
|
||||
|
||||
|
||||
@ -92,13 +92,12 @@ public static class InfrastructureExtensions
|
||||
var env = app.Environment;
|
||||
var appOptions = app.GetOptions<AppOptions>("AppOptions");
|
||||
|
||||
app.UseProblemDetails();
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseCorrelationId();
|
||||
app.UseRouting();
|
||||
app.UseHttpMetrics();
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseProblemDetails();
|
||||
app.UseCustomHealthCheck();
|
||||
app.MapMetrics();
|
||||
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));
|
||||
|
||||
@ -10,8 +10,8 @@ public static class MediatRExtensions
|
||||
public static IServiceCollection AddCustomMediatR(this IServiceCollection services)
|
||||
{
|
||||
services.AddMediatR(typeof(BookingRoot).Assembly);
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -1,9 +1,3 @@
|
||||
namespace Flight.Aircrafts.Dtos;
|
||||
|
||||
public record AircraftResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; init; }
|
||||
public string Model { get; init; }
|
||||
public int ManufacturingYear { get; init; }
|
||||
}
|
||||
public record AircraftResponseDto(long Id, string Name, string Model, int ManufacturingYear);
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Aircrafts.Features.CreateAircraft.Commands.V1;
|
||||
using Flight.Aircrafts.Features.CreateAircraft.Commands.V1.Reads;
|
||||
using Flight.Aircrafts.Features.CreateAircraft.Dtos.V1;
|
||||
using Flight.Aircrafts.Models;
|
||||
using Flight.Aircrafts.Models.Reads;
|
||||
using Flight.Airports.Features.CreateAirport.Commands.V1;
|
||||
using Mapster;
|
||||
|
||||
namespace Flight.Aircrafts.Features;
|
||||
@ -17,5 +20,8 @@ public class AircraftMappings : IRegister
|
||||
config.NewConfig<Aircraft, AircraftReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.AircraftId, s => s.Id);
|
||||
|
||||
config.NewConfig<CreateAircraftRequestDto, CreateAircraftCommand>()
|
||||
.ConstructUsing(x => new CreateAircraftCommand(x.Name, x.Model, x.ManufacturingYear));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,21 +2,4 @@
|
||||
|
||||
namespace Flight.Aircrafts.Features.CreateAircraft.Commands.V1.Reads;
|
||||
|
||||
public class CreateAircraftMongoCommand : InternalCommand
|
||||
{
|
||||
public CreateAircraftMongoCommand(long id, string name, string model, int manufacturingYear, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Model = model;
|
||||
ManufacturingYear = manufacturingYear;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
|
||||
public long Id { get; }
|
||||
public string Name { get; }
|
||||
public string Model { get; }
|
||||
public int ManufacturingYear { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record CreateAircraftMongoCommand(long Id, string Name, string Model, int ManufacturingYear, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -32,7 +32,7 @@ public class CreateAircraftMongoCommandHandler : ICommandHandler<CreateAircraftM
|
||||
var aircraftReadModel = _mapper.Map<AircraftReadModel>(command);
|
||||
|
||||
var aircraft = await _flightReadDbContext.Aircraft.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == aircraftReadModel.Id, cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.AircraftId == aircraftReadModel.AircraftId, cancellationToken);
|
||||
|
||||
if (aircraft is not null)
|
||||
throw new AircraftAlreadyExistException();
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
namespace Flight.Aircrafts.Features.CreateAircraft.Dtos.V1;
|
||||
|
||||
public record CreateAircraftRequestDto(string Name, string Model, int ManufacturingYear);
|
||||
|
||||
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Aircrafts.Dtos;
|
||||
using Flight.Aircrafts.Features.CreateAircraft.Commands.V1;
|
||||
using Flight.Aircrafts.Features.CreateAircraft.Dtos.V1;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -29,8 +31,11 @@ public class CreateAircraftEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CreateAircraft(CreateAircraftCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CreateAircraft(CreateAircraftRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CreateAircraftCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -6,10 +6,6 @@ namespace Flight.Aircrafts.Models;
|
||||
|
||||
public record Aircraft : Aggregate<long>
|
||||
{
|
||||
public Aircraft()
|
||||
{
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Model { get; private set; }
|
||||
public int ManufacturingYear { get; private set; }
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Airports.Features.CreateAirport.Commands.V1;
|
||||
using Flight.Airports.Features.CreateAirport.Commands.V1.Reads;
|
||||
using Flight.Airports.Features.CreateAirport.Dtos.V1;
|
||||
using Flight.Airports.Models;
|
||||
using Flight.Airports.Models.Reads;
|
||||
using Mapster;
|
||||
@ -17,5 +19,8 @@ public class AirportMappings : IRegister
|
||||
config.NewConfig<Airport, AirportReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.AirportId, s => s.Id);
|
||||
|
||||
config.NewConfig<CreateAirportRequestDto, CreateAirportCommand>()
|
||||
.ConstructUsing(x => new CreateAirportCommand(x.Name, x.Address, x.Code));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
namespace Flight.Airports.Dtos;
|
||||
public record AirportResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; init; }
|
||||
public string Address { get; init; }
|
||||
public string Code { get; init; }
|
||||
}
|
||||
|
||||
public record AirportResponseDto(long Id, string Name, string Address, string Code);
|
||||
|
||||
@ -2,19 +2,4 @@
|
||||
|
||||
namespace Flight.Airports.Features.CreateAirport.Commands.V1.Reads;
|
||||
|
||||
public class CreateAirportMongoCommand : InternalCommand
|
||||
{
|
||||
public CreateAirportMongoCommand(long id, string name, string address, string code, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
Address = address;
|
||||
Code = code;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string Address { get; }
|
||||
public string Code { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record CreateAirportMongoCommand(long Id, string Name, string Address, string Code, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -32,7 +32,7 @@ public class CreateAirportMongoCommandHandler : ICommandHandler<CreateAirportMon
|
||||
var airportReadModel = _mapper.Map<AirportReadModel>(command);
|
||||
|
||||
var aircraft = await _flightReadDbContext.Airport.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == airportReadModel.Id, cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.AirportId == airportReadModel.AirportId, cancellationToken);
|
||||
|
||||
if (aircraft is not null)
|
||||
throw new AirportAlreadyExistException();
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Flight.Airports.Features.CreateAirport.Dtos.V1;
|
||||
|
||||
public record CreateAirportRequestDto(string Name, string Address, string Code);
|
||||
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Airports.Dtos;
|
||||
using Flight.Airports.Features.CreateAirport.Commands.V1;
|
||||
using Flight.Airports.Features.CreateAirport.Dtos.V1;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -29,8 +31,11 @@ public class CreateAirportEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CreateAirport(CreateAirportCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CreateAirport(CreateAirportRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CreateAirportCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -6,10 +6,6 @@ namespace Flight.Airports.Models;
|
||||
|
||||
public record Airport : Aggregate<long>
|
||||
{
|
||||
public Airport()
|
||||
{
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
public string Address { get; private set; }
|
||||
public string Code { get; private set; }
|
||||
|
||||
@ -7,5 +7,5 @@ public class AirportReadModel
|
||||
public string Name { get; init; }
|
||||
public string Address { get; init; }
|
||||
public string Code { get; init; }
|
||||
public bool IsDeleted { get; set; }
|
||||
public bool IsDeleted { get; init; }
|
||||
}
|
||||
|
||||
@ -90,8 +90,6 @@ public static class InfrastructureExtensions
|
||||
|
||||
SnowFlakIdGenerator.Configure(1);
|
||||
|
||||
builder.Services.AddCachingRequest(new List<Assembly> {typeof(FlightRoot).Assembly});
|
||||
|
||||
builder.Services.AddEasyCaching(options => { options.UseInMemory(configuration, "mem"); });
|
||||
|
||||
return builder;
|
||||
@ -103,11 +101,11 @@ public static class InfrastructureExtensions
|
||||
var env = app.Environment;
|
||||
var appOptions = app.GetOptions<AppOptions>("AppOptions");
|
||||
|
||||
app.UseProblemDetails();
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseCorrelationId();
|
||||
app.UseHttpMetrics();
|
||||
app.UseMigration<FlightDbContext>(env);
|
||||
app.UseProblemDetails();
|
||||
app.UseHttpsRedirection();
|
||||
app.MapMetrics();
|
||||
app.UseCustomHealthCheck();
|
||||
|
||||
@ -12,10 +12,11 @@ public static class MediatRExtensions
|
||||
public static IServiceCollection AddCustomMediatR(this IServiceCollection services)
|
||||
{
|
||||
services.AddMediatR(typeof(FlightRoot).Assembly);
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(CachingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(InvalidateCachingBehavior<,>));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -2,18 +2,7 @@ using System;
|
||||
using Flight.Flights.Models;
|
||||
|
||||
namespace Flight.Flights.Dtos;
|
||||
public record FlightResponseDto
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public string FlightNumber { get; init; }
|
||||
public long FlightId { get; set; }
|
||||
public long AircraftId { get; init; }
|
||||
public long DepartureAirportId { get; init; }
|
||||
public DateTime DepartureDate { get; init; }
|
||||
public DateTime ArriveDate { get; init; }
|
||||
public long ArriveAirportId { get; init; }
|
||||
public decimal DurationMinutes { get; init; }
|
||||
public DateTime FlightDate { get; init; }
|
||||
public Enums.FlightStatus Status { get; init; }
|
||||
public decimal Price { get; init; }
|
||||
}
|
||||
|
||||
public record FlightResponseDto(long Id, string FlightNumber, long AircraftId, long DepartureAirportId,
|
||||
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
|
||||
Enums.FlightStatus Status, decimal Price);
|
||||
|
||||
@ -40,6 +40,8 @@ public class CreateFlightCommandHandler : ICommandHandler<CreateFlightCommand, F
|
||||
|
||||
var newFlight = await _flightDbContext.Flights.AddAsync(flightEntity, cancellationToken);
|
||||
|
||||
return _mapper.Map<FlightResponseDto>(newFlight.Entity);
|
||||
var f = _mapper.Map<FlightResponseDto>(newFlight.Entity);
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,36 +3,6 @@ using BuildingBlocks.Core.Event;
|
||||
|
||||
namespace Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
|
||||
|
||||
public class CreateFlightMongoCommand : InternalCommand
|
||||
{
|
||||
public CreateFlightMongoCommand(long id, string flightNumber, long aircraftId, DateTime departureDate,
|
||||
long departureAirportId,
|
||||
DateTime arriveDate, long arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
|
||||
decimal price, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
FlightNumber = flightNumber;
|
||||
AircraftId = aircraftId;
|
||||
DepartureDate = departureDate;
|
||||
DepartureAirportId = departureAirportId;
|
||||
ArriveDate = arriveDate;
|
||||
ArriveAirportId = arriveAirportId;
|
||||
DurationMinutes = durationMinutes;
|
||||
FlightDate = flightDate;
|
||||
Status = status;
|
||||
Price = price;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public string FlightNumber { get; }
|
||||
public long AircraftId { get; }
|
||||
public DateTime DepartureDate { get; }
|
||||
public long DepartureAirportId { get; }
|
||||
public DateTime ArriveDate { get; }
|
||||
public long ArriveAirportId { get; }
|
||||
public decimal DurationMinutes { get; }
|
||||
public DateTime FlightDate { get; }
|
||||
public Enums.FlightStatus Status { get; }
|
||||
public decimal Price { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record CreateFlightMongoCommand(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
|
||||
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
|
||||
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -33,7 +33,7 @@ public class CreateFlightMongoCommandHandler : ICommandHandler<CreateFlightMongo
|
||||
var flightReadModel = _mapper.Map<FlightReadModel>(command);
|
||||
|
||||
var flight = await _flightReadDbContext.Flight.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == flightReadModel.Id && !x.IsDeleted, cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.FlightId == flightReadModel.FlightId && !x.IsDeleted, cancellationToken);
|
||||
|
||||
if (flight is not null)
|
||||
throw new FlightAlreadyExistException();
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace Flight.Flights.Features.CreateFlight.Dtos.V1;
|
||||
|
||||
public record CreateFlightRequestDto(string FlightNumber, long AircraftId, long DepartureAirportId,
|
||||
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId,
|
||||
decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price);
|
||||
@ -3,6 +3,9 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Flights.Dtos;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1;
|
||||
using Flight.Flights.Features.CreateFlight.Dtos.V1;
|
||||
using Mapster;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -29,8 +32,11 @@ public class CreateFlightEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CreateFlight(CreateFlightCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CreateFlight(CreateFlightRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CreateFlightCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -3,36 +3,6 @@ using BuildingBlocks.Core.Event;
|
||||
|
||||
namespace Flight.Flights.Features.DeleteFlight.Commands.V1.Reads;
|
||||
|
||||
public class DeleteFlightMongoCommand : InternalCommand
|
||||
{
|
||||
public DeleteFlightMongoCommand(long id, string flightNumber, long aircraftId, DateTime departureDate,
|
||||
long departureAirportId,
|
||||
DateTime arriveDate, long arriveAirportId, decimal durationMinutes, DateTime flightDate, Enums.FlightStatus status,
|
||||
decimal price, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
FlightNumber = flightNumber;
|
||||
AircraftId = aircraftId;
|
||||
DepartureDate = departureDate;
|
||||
DepartureAirportId = departureAirportId;
|
||||
ArriveDate = arriveDate;
|
||||
ArriveAirportId = arriveAirportId;
|
||||
DurationMinutes = durationMinutes;
|
||||
FlightDate = flightDate;
|
||||
Status = status;
|
||||
Price = price;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public string FlightNumber { get; }
|
||||
public long AircraftId { get; }
|
||||
public DateTime DepartureDate { get; }
|
||||
public long DepartureAirportId { get; }
|
||||
public DateTime ArriveDate { get; }
|
||||
public long ArriveAirportId { get; }
|
||||
public decimal DurationMinutes { get; }
|
||||
public DateTime FlightDate { get; }
|
||||
public Enums.FlightStatus Status { get; }
|
||||
public decimal Price { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record DeleteFlightMongoCommand(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
|
||||
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
|
||||
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
using AutoMapper;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Flights.Dtos;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1.Reads;
|
||||
using Flight.Flights.Features.CreateFlight.Dtos.V1;
|
||||
using Flight.Flights.Features.DeleteFlight.Commands.V1.Reads;
|
||||
using Flight.Flights.Features.UpdateFlight.Commands.V1;
|
||||
using Flight.Flights.Features.UpdateFlight.Commands.V1.Reads;
|
||||
using Flight.Flights.Features.UpdateFlight.Dtos;
|
||||
using Flight.Flights.Models.Reads;
|
||||
using Mapster;
|
||||
|
||||
@ -14,16 +18,30 @@ public class FlightMappings : IRegister
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.NewConfig<Models.Flight, FlightResponseDto>()
|
||||
.Map(d => d.FlightId, s => s.Id);
|
||||
.ConstructUsing(x => new FlightResponseDto(x.Id, x.FlightNumber, x.AircraftId, x.DepartureAirportId, x.DepartureDate,
|
||||
x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.Price));
|
||||
|
||||
config.NewConfig<CreateFlightMongoCommand, FlightReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.FlightId, s => s.Id);
|
||||
|
||||
config.NewConfig<Models.Flight, FlightReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.FlightId, s => s.Id);
|
||||
|
||||
config.NewConfig<UpdateFlightMongoCommand, FlightReadModel>()
|
||||
.Map(d => d.FlightId, s => s.Id);
|
||||
|
||||
config.NewConfig<DeleteFlightMongoCommand, FlightReadModel>()
|
||||
.Map(d => d.FlightId, s => s.Id);
|
||||
|
||||
config.NewConfig<CreateFlightRequestDto, CreateFlightCommand>()
|
||||
.ConstructUsing(x => new CreateFlightCommand(x.FlightNumber, x.AircraftId, x.DepartureAirportId,
|
||||
x.DepartureDate, x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.Price));
|
||||
|
||||
config.NewConfig<UpdateFlightRequestDto, UpdateFlightCommand>()
|
||||
.ConstructUsing(x => new UpdateFlightCommand(x.Id, x.FlightNumber, x.AircraftId, x.DepartureAirportId, x.DepartureDate,
|
||||
x.ArriveDate, x.ArriveAirportId, x.DurationMinutes, x.FlightDate, x.Status, x.IsDeleted, x.Price));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,4 +36,4 @@ public class GetAvailableFlightsEndpoint : IMinimalEndpoint
|
||||
|
||||
return Results.Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,29 +1,3 @@
|
||||
// using System.Threading;
|
||||
// using System.Threading.Tasks;
|
||||
// using BuildingBlocks.Web;
|
||||
// using Flight.Flights.Features.GetFlightById.Queries.V1;
|
||||
// using Microsoft.AspNetCore.Authorization;
|
||||
// using Microsoft.AspNetCore.Http;
|
||||
// using Microsoft.AspNetCore.Mvc;
|
||||
// using Swashbuckle.AspNetCore.Annotations;
|
||||
//
|
||||
// namespace Flight.Flights.Features.GetFlightById.Endpoints.V1;
|
||||
//
|
||||
// [Route(BaseApiPath + "/flight")]
|
||||
// public class GetFlightByIdEndpoint : BaseController
|
||||
// {
|
||||
// [Authorize]
|
||||
// [HttpGet("{id}")]
|
||||
// [ProducesResponseType(StatusCodes.Status200OK)]
|
||||
// [ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
// [SwaggerOperation(Summary = "Get flight by id", Description = "Get flight by id")]
|
||||
// public async Task<ActionResult> GetById([FromRoute] GetFlightByIdQuery query, CancellationToken cancellationToken)
|
||||
// {
|
||||
// var result = await Mediator.Send(query, cancellationToken);
|
||||
// return Ok(result);
|
||||
// }
|
||||
// }
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
@ -61,4 +35,4 @@ public class GetFlightByIdEndpoint : IMinimalEndpoint
|
||||
|
||||
return Results.Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,36 +3,6 @@ using BuildingBlocks.Core.Event;
|
||||
|
||||
namespace Flight.Flights.Features.UpdateFlight.Commands.V1.Reads;
|
||||
|
||||
public class UpdateFlightMongoCommand : InternalCommand
|
||||
{
|
||||
public UpdateFlightMongoCommand(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
|
||||
long DepartureAirportId,
|
||||
DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status,
|
||||
decimal Price, bool IsDeleted)
|
||||
{
|
||||
this.Id = Id;
|
||||
this.FlightNumber = FlightNumber;
|
||||
this.AircraftId = AircraftId;
|
||||
this.DepartureDate = DepartureDate;
|
||||
this.DepartureAirportId = DepartureAirportId;
|
||||
this.ArriveDate = ArriveDate;
|
||||
this.ArriveAirportId = ArriveAirportId;
|
||||
this.DurationMinutes = DurationMinutes;
|
||||
this.FlightDate = FlightDate;
|
||||
this.Status = Status;
|
||||
this.Price = Price;
|
||||
this.IsDeleted = IsDeleted;
|
||||
}
|
||||
|
||||
public string FlightNumber { get; }
|
||||
public long AircraftId { get; }
|
||||
public DateTime DepartureDate { get; }
|
||||
public long DepartureAirportId { get; }
|
||||
public DateTime ArriveDate { get; }
|
||||
public long ArriveAirportId { get; }
|
||||
public decimal DurationMinutes { get; }
|
||||
public DateTime FlightDate { get; }
|
||||
public Enums.FlightStatus Status { get; }
|
||||
public decimal Price { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record UpdateFlightMongoCommand(long Id, string FlightNumber, long AircraftId, DateTime DepartureDate,
|
||||
long DepartureAirportId, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
|
||||
Enums.FlightStatus Status, decimal Price, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -6,21 +6,9 @@ using Flight.Flights.Dtos;
|
||||
|
||||
namespace Flight.Flights.Features.UpdateFlight.Commands.V1;
|
||||
|
||||
public record UpdateFlightCommand : ICommand<FlightResponseDto>, IInvalidateCacheRequest, IInternalCommand
|
||||
public record UpdateFlightCommand(long Id, string FlightNumber, long AircraftId, long DepartureAirportId,
|
||||
DateTime DepartureDate, DateTime ArriveDate, long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate,
|
||||
Enums.FlightStatus Status, bool IsDeleted, decimal Price) : ICommand<FlightResponseDto>, IInternalCommand, IInvalidateCacheRequest
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public string FlightNumber { get; init; }
|
||||
public long AircraftId { get; init; }
|
||||
public long DepartureAirportId { get; init; }
|
||||
public DateTime DepartureDate { get; init; }
|
||||
public DateTime ArriveDate { get; init; }
|
||||
public long ArriveAirportId { get; init; }
|
||||
public decimal DurationMinutes { get; init; }
|
||||
public DateTime FlightDate { get; init; }
|
||||
|
||||
public Enums.FlightStatus Status { get; init; }
|
||||
|
||||
public bool IsDeleted { get; init; } = false;
|
||||
public decimal Price { get; init; }
|
||||
public string CacheKey => "GetAvailableFlightsQuery";
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Flight.Flights.Features.UpdateFlight.Dtos;
|
||||
|
||||
public record UpdateFlightRequestDto(long Id, string FlightNumber, long AircraftId, long DepartureAirportId, DateTime DepartureDate, DateTime ArriveDate,
|
||||
long ArriveAirportId, decimal DurationMinutes, DateTime FlightDate, Enums.FlightStatus Status, decimal Price, bool IsDeleted);
|
||||
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Flights.Dtos;
|
||||
using Flight.Flights.Features.UpdateFlight.Commands.V1;
|
||||
using Flight.Flights.Features.UpdateFlight.Dtos;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -29,10 +31,12 @@ public class UpdateFlightEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> UpdateFlight(UpdateFlightCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> UpdateFlight(UpdateFlightRequestDto request, IMediator mediator, IMapper mapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<UpdateFlightCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Flight.Flights.Models.Reads;
|
||||
|
||||
|
||||
@ -1,12 +1,3 @@
|
||||
using Flight.Seats.Models;
|
||||
|
||||
namespace Flight.Seats.Dtos;
|
||||
|
||||
public record SeatResponseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string SeatNumber { get; init; }
|
||||
public Enums.SeatType Type { get; init; }
|
||||
public Enums.SeatClass Class { get; init; }
|
||||
public long FlightId { get; init; }
|
||||
}
|
||||
public record SeatResponseDto(long Id, string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId);
|
||||
|
||||
@ -2,23 +2,5 @@
|
||||
|
||||
namespace Flight.Seats.Features.CreateSeat.Commands.V1.Reads;
|
||||
|
||||
public class CreateSeatMongoCommand : InternalCommand
|
||||
{
|
||||
public CreateSeatMongoCommand(long id, string seatNumber, Enums.SeatType type, Enums.SeatClass @class,
|
||||
long flightId, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
SeatNumber = seatNumber;
|
||||
Type = type;
|
||||
Class = @class;
|
||||
FlightId = flightId;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public long Id { get; }
|
||||
public string SeatNumber { get; }
|
||||
public Enums.SeatType Type { get; }
|
||||
public Enums.SeatClass Class { get; }
|
||||
public long FlightId { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record CreateSeatMongoCommand(long Id, string SeatNumber, Enums.SeatType Type,
|
||||
Enums.SeatClass Class, long FlightId, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -32,7 +32,7 @@ public class CreateSeatMongoCommandHandler : ICommandHandler<CreateSeatMongoComm
|
||||
var seatReadModel = _mapper.Map<SeatReadModel>(command);
|
||||
|
||||
var seat = await _flightReadDbContext.Seat.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.Id == seatReadModel.Id, cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.SeatId == seatReadModel.SeatId, cancellationToken);
|
||||
|
||||
if (seat is not null)
|
||||
throw new SeatAlreadyExistException();
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Flight.Seats.Features.CreateSeat.Dtos.V1;
|
||||
|
||||
public record CreateSeatRequestDto(string SeatNumber, Enums.SeatType Type, Enums.SeatClass Class, long FlightId);
|
||||
@ -1,34 +1,10 @@
|
||||
// using System.Threading;
|
||||
// using System.Threading.Tasks;
|
||||
// using BuildingBlocks.Web;
|
||||
// using Flight.Seats.Features.CreateSeat.Commands.V1;
|
||||
// using Microsoft.AspNetCore.Http;
|
||||
// using Microsoft.AspNetCore.Mvc;
|
||||
// using Swashbuckle.AspNetCore.Annotations;
|
||||
//
|
||||
// namespace Flight.Seats.Features.CreateSeat.Endpoints.V1;
|
||||
//
|
||||
// [Route(BaseApiPath + "/flight/seat")]
|
||||
// public class CreateSeatEndpoint : BaseController
|
||||
// {
|
||||
// [HttpPost]
|
||||
// [ProducesResponseType(StatusCodes.Status201Created)]
|
||||
// [ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
// [SwaggerOperation(Summary = "Create new seat", Description = "Create new seat")]
|
||||
// public async Task<ActionResult> Create(CreateSeatCommand command, CancellationToken cancellationToken)
|
||||
// {
|
||||
// var result = await Mediator.Send(command, cancellationToken);
|
||||
//
|
||||
// return Ok(result);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Seats.Dtos;
|
||||
using Flight.Seats.Features.CreateSeat.Commands.V1;
|
||||
using Flight.Seats.Features.CreateSeat.Dtos.V1;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -55,10 +31,13 @@ public class CreateSeatEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CreateSeat(CreateSeatCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CreateSeat(CreateSeatRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CreateSeatCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,22 +2,5 @@
|
||||
|
||||
namespace Flight.Seats.Features.ReserveSeat.Commands.V1.Reads;
|
||||
|
||||
public class ReserveSeatMongoCommand : InternalCommand
|
||||
{
|
||||
public ReserveSeatMongoCommand(long id, string seatNumber, Enums.SeatType type, Enums.SeatClass @class, long flightId,
|
||||
bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
SeatNumber = seatNumber;
|
||||
Type = type;
|
||||
Class = @class;
|
||||
FlightId = flightId;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public string SeatNumber { get; }
|
||||
public Enums.SeatType Type { get; }
|
||||
public Enums.SeatClass Class { get; }
|
||||
public long FlightId { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record ReserveSeatMongoCommand(long Id, string SeatNumber, Enums.SeatType Type,
|
||||
Enums.SeatClass Class, long FlightId, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
namespace Flight.Seats.Features.ReserveSeat.Dtos.V1;
|
||||
|
||||
|
||||
public record ReserveSeatRequestDto(long FlightId, string SeatNumber);
|
||||
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Flight.Seats.Dtos;
|
||||
using Flight.Seats.Features.ReserveSeat.Commands.V1;
|
||||
using Flight.Seats.Features.ReserveSeat.Dtos.V1;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -29,10 +31,12 @@ public class ReserveSeatEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> ReserveSeat(ReserveSeatCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> ReserveSeat(ReserveSeatRequestDto request, IMediator mediator, IMapper mapper, CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<ReserveSeatCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Flight.Seats.Dtos;
|
||||
using Flight.Seats.Features.CreateSeat.Commands.V1;
|
||||
using Flight.Seats.Features.CreateSeat.Commands.V1.Reads;
|
||||
using Flight.Seats.Features.CreateSeat.Dtos.V1;
|
||||
using Flight.Seats.Features.ReserveSeat.Commands.V1;
|
||||
using Flight.Seats.Features.ReserveSeat.Commands.V1.Reads;
|
||||
using Flight.Seats.Features.ReserveSeat.Dtos.V1;
|
||||
using Flight.Seats.Models;
|
||||
using Flight.Seats.Models.Reads;
|
||||
using Mapster;
|
||||
@ -12,14 +16,24 @@ public class SeatMappings : IRegister
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.NewConfig<Seat, SeatResponseDto>();
|
||||
config.NewConfig<Seat, SeatResponseDto>()
|
||||
.ConstructUsing(x => new SeatResponseDto(x.Id, x.SeatNumber, x.Type, x.Class, x.FlightId));
|
||||
|
||||
config.NewConfig<CreateSeatMongoCommand, SeatReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.SeatId, s => s.Id);
|
||||
|
||||
config.NewConfig<Seat, SeatReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.SeatId, s => s.Id);
|
||||
|
||||
config.NewConfig<ReserveSeatMongoCommand, SeatReadModel>()
|
||||
.Map(d => d.SeatId, s => s.Id);
|
||||
|
||||
config.NewConfig<CreateSeatRequestDto, CreateSeatCommand>()
|
||||
.ConstructUsing(x => new CreateSeatCommand(x.SeatNumber, x.Type, x.Class, x.FlightId));
|
||||
|
||||
config.NewConfig<ReserveSeatRequestDto, ReserveSeatCommand>()
|
||||
.ConstructUsing(x => new ReserveSeatCommand(x.FlightId, x.SeatNumber));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using Flight.Flights.Features.CreateFlight;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1;
|
||||
using Flight.Flights.Features.CreateFlight.Commands.V1;
|
||||
|
||||
namespace Integration.Test.Fakes;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public class GetFlightByIdTests : IntegrationTestBase<Program, FlightDbContext,
|
||||
|
||||
// Assert
|
||||
response.Should().NotBeNull();
|
||||
response?.FlightId.Should().Be(command.Id);
|
||||
response?.Id.Should().Be(command.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@ -84,6 +84,7 @@ public static class InfrastructureExtensions
|
||||
var env = app.Environment;
|
||||
var appOptions = app.GetOptions<AppOptions>("AppOptions");
|
||||
|
||||
app.UseProblemDetails();
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseMigration<IdentityContext>(env);
|
||||
app.UseCorrelationId();
|
||||
|
||||
@ -10,8 +10,8 @@ public static class MediatRExtensions
|
||||
public static IServiceCollection AddCustomMediatR(this IServiceCollection services)
|
||||
{
|
||||
services.AddMediatR(typeof(IdentityRoot).Assembly);
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -1,13 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Identity.Identity.Dtos;
|
||||
|
||||
public record RegisterNewUserResponseDto
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public string FirstName { get; init; }
|
||||
public string LastName { get; init; }
|
||||
public string Username { get; init; }
|
||||
|
||||
public string PassportNumber { get; set; }
|
||||
}
|
||||
public record RegisterNewUserResponseDto(long Id, string FirstName, string LastName, string Username, string PassportNumber);
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
using Identity.Identity.Features.RegisterNewUser.Commands.V1;
|
||||
using Identity.Identity.Features.RegisterNewUser.Dtos.V1;
|
||||
using Mapster;
|
||||
|
||||
namespace Identity.Identity.Features;
|
||||
|
||||
public class IdentityMappings : IRegister
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.NewConfig<RegisterNewUserRequestDto, RegisterNewUserCommand>()
|
||||
.ConstructUsing(x => new RegisterNewUserCommand(x.FirstName, x.LastName, x.Username, x.Email,
|
||||
x.Password, x.ConfirmPassword, x.PassportNumber));
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ public class RegisterNewUserCommandHandler : ICommandHandler<RegisterNewUserComm
|
||||
{
|
||||
Guard.Against.Null(command, nameof(command));
|
||||
|
||||
var applicationUser = new ApplicationUser
|
||||
var applicationUser = new ApplicationUser()
|
||||
{
|
||||
FirstName = command.FirstName,
|
||||
LastName = command.LastName,
|
||||
@ -51,13 +51,7 @@ public class RegisterNewUserCommandHandler : ICommandHandler<RegisterNewUserComm
|
||||
await _eventDispatcher.SendAsync(new UserCreated(applicationUser.Id, applicationUser.FirstName + " " + applicationUser.LastName,
|
||||
applicationUser.PassPortNumber),cancellationToken: cancellationToken);
|
||||
|
||||
return new RegisterNewUserResponseDto
|
||||
{
|
||||
Id = applicationUser.Id,
|
||||
FirstName = applicationUser.FirstName,
|
||||
LastName = applicationUser.LastName,
|
||||
Username = applicationUser.UserName,
|
||||
PassportNumber = applicationUser.PassPortNumber
|
||||
};
|
||||
return new RegisterNewUserResponseDto(applicationUser.Id, applicationUser.FirstName, applicationUser.LastName,
|
||||
applicationUser.UserName, applicationUser.PassPortNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
namespace Identity.Identity.Features.RegisterNewUser.Dtos.V1;
|
||||
|
||||
public record RegisterNewUserRequestDto(string FirstName, string LastName, string Username, string Email,
|
||||
string Password, string ConfirmPassword, string PassportNumber);
|
||||
@ -3,6 +3,8 @@ using System.Threading.Tasks;
|
||||
using BuildingBlocks.Web;
|
||||
using Identity.Identity.Dtos;
|
||||
using Identity.Identity.Features.RegisterNewUser.Commands.V1;
|
||||
using Identity.Identity.Features.RegisterNewUser.Dtos.V1;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -28,8 +30,11 @@ public class RegisterNewUserEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> RegisterNewUser(RegisterNewUserCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> RegisterNewUser(RegisterNewUserRequestDto request, IMediator mediator, IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<RegisterNewUserCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -4,7 +4,7 @@ namespace Identity.Identity.Models;
|
||||
|
||||
public class ApplicationUser : IdentityUser<long>
|
||||
{
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string PassPortNumber { get; set; }
|
||||
public string FirstName { get; init; }
|
||||
public string LastName { get; init; }
|
||||
public string PassPortNumber { get; init; }
|
||||
}
|
||||
|
||||
@ -1,27 +1,5 @@
|
||||
using BuildingBlocks.EFCore;
|
||||
using BuildingBlocks.Exception;
|
||||
using BuildingBlocks.HealthCheck;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using BuildingBlocks.Jwt;
|
||||
using BuildingBlocks.Logging;
|
||||
using BuildingBlocks.Mapster;
|
||||
using BuildingBlocks.MassTransit;
|
||||
using BuildingBlocks.Mongo;
|
||||
using BuildingBlocks.OpenTelemetry;
|
||||
using BuildingBlocks.PersistMessageProcessor;
|
||||
using BuildingBlocks.Swagger;
|
||||
using BuildingBlocks.Web;
|
||||
using Figgle;
|
||||
using FluentValidation;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Passenger;
|
||||
using Passenger.Data;
|
||||
using Passenger.Extensions;
|
||||
using Passenger.Extensions.Infrastructure;
|
||||
using Passenger.GrpcServer.Services;
|
||||
using Prometheus;
|
||||
using Serilog;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
||||
@ -91,11 +91,11 @@ public static class InfrastructureExtensions
|
||||
var env = app.Environment;
|
||||
var appOptions = app.GetOptions<AppOptions>("AppOptions");
|
||||
|
||||
app.UseProblemDetails();
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseMigration<PassengerDbContext>(env);
|
||||
app.UseCorrelationId();
|
||||
app.UseHttpMetrics();
|
||||
app.UseProblemDetails();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseCustomHealthCheck();
|
||||
app.MapMetrics();
|
||||
|
||||
@ -11,9 +11,9 @@ public static class MediatRExtensions
|
||||
public static IServiceCollection AddCustomMediatR(this IServiceCollection services)
|
||||
{
|
||||
services.AddMediatR(typeof(PassengerRoot).Assembly);
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(EfTxBehavior<,>));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@ -2,22 +2,5 @@
|
||||
|
||||
namespace Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1.Reads;
|
||||
|
||||
public class CompleteRegisterPassengerMongoCommand : InternalCommand
|
||||
{
|
||||
public CompleteRegisterPassengerMongoCommand(long id, string passportNumber, string name,
|
||||
Enums.PassengerType passengerType, int age, bool isDeleted)
|
||||
{
|
||||
Id = id;
|
||||
PassportNumber = passportNumber;
|
||||
Name = name;
|
||||
PassengerType = passengerType;
|
||||
Age = age;
|
||||
IsDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public string PassportNumber { get; }
|
||||
public string Name { get; }
|
||||
public Enums.PassengerType PassengerType { get; }
|
||||
public int Age { get; }
|
||||
public bool IsDeleted { get; }
|
||||
}
|
||||
public record CompleteRegisterPassengerMongoCommand(long Id, string PassportNumber, string Name,
|
||||
Enums.PassengerType PassengerType, int Age, bool IsDeleted) : InternalCommand;
|
||||
|
||||
@ -29,7 +29,7 @@ public class CompleteRegisterPassengerMongoCommandHandler : ICommandHandler<Comp
|
||||
var passengerReadModel = _mapper.Map<PassengerReadModel>(command);
|
||||
|
||||
var passenger = await _passengerReadDbContext.Passenger.AsQueryable()
|
||||
.FirstOrDefaultAsync(x => x.PassengerId == command.Id && !x.IsDeleted, cancellationToken);
|
||||
.FirstOrDefaultAsync(x => x.PassengerId == passengerReadModel.PassengerId && !x.IsDeleted, cancellationToken);
|
||||
|
||||
if (passenger is not null)
|
||||
{
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
namespace Passenger.Passengers.Features.CompleteRegisterPassenger.Dtos.V1;
|
||||
|
||||
public record CompleteRegisterPassengerRequestDto(string PassportNumber, Enums.PassengerType PassengerType, int Age);
|
||||
@ -1,12 +1,12 @@
|
||||
using BuildingBlocks.Web;
|
||||
using MapsterMapper;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Passenger.Passengers.Dtos;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Dtos.V1;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace Passenger.Passengers.Features.CompleteRegisterPassenger.Endpoints.V1;
|
||||
@ -29,8 +29,11 @@ public class CompleteRegisterPassengerEndpoint : IMinimalEndpoint
|
||||
return endpoints;
|
||||
}
|
||||
|
||||
private async Task<IResult> CompleteRegisterPassenger(CompleteRegisterPassengerCommand command, IMediator mediator, CancellationToken cancellationToken)
|
||||
private async Task<IResult> CompleteRegisterPassenger(CompleteRegisterPassengerRequestDto request, IMapper mapper,
|
||||
IMediator mediator, CancellationToken cancellationToken)
|
||||
{
|
||||
var command = mapper.Map<CompleteRegisterPassengerCommand>(request);
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
|
||||
return Results.Ok(result);
|
||||
|
||||
@ -3,7 +3,9 @@ using BuildingBlocks.Contracts.EventBus.Messages;
|
||||
using BuildingBlocks.IdsGenerator;
|
||||
using Mapster;
|
||||
using Passenger.Passengers.Dtos;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Commands.V1.Reads;
|
||||
using Passenger.Passengers.Features.CompleteRegisterPassenger.Dtos.V1;
|
||||
using Passenger.Passengers.Models.Reads;
|
||||
|
||||
namespace Passenger.Passengers.Features;
|
||||
@ -15,5 +17,8 @@ public class PassengerMappings : IRegister
|
||||
config.NewConfig<CompleteRegisterPassengerMongoCommand, PassengerReadModel>()
|
||||
.Map(d => d.Id, s => SnowFlakIdGenerator.NewId())
|
||||
.Map(d => d.PassengerId, s => s.Id);
|
||||
|
||||
config.NewConfig<CompleteRegisterPassengerRequestDto, CompleteRegisterPassengerCommand>()
|
||||
.ConstructUsing(x => new CompleteRegisterPassengerCommand(x.PassportNumber, x.PassengerType, x.Age));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,9 +4,9 @@ public class PassengerReadModel
|
||||
{
|
||||
public long Id { get; init; }
|
||||
public long PassengerId { get; init; }
|
||||
public string PassportNumber { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public Enums.PassengerType PassengerType { get; private set; }
|
||||
public int Age { get; private set; }
|
||||
public string PassportNumber { get; init; }
|
||||
public string Name { get; init; }
|
||||
public Enums.PassengerType PassengerType { get; init; }
|
||||
public int Age { get; init; }
|
||||
public bool IsDeleted { get; init; }
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user