add vehicles hierarchy management
This commit is contained in:
parent
201e6e7dfc
commit
3ebd0c3a2c
23
src/Application/Aircrafts/AircraftDto.cs
Normal file
23
src/Application/Aircrafts/AircraftDto.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts;
|
||||||
|
|
||||||
|
public sealed class AircraftDto : IMapFrom<Aircraft>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<Aircraft, AircraftDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;
|
||||||
|
|
||||||
|
public record AddAircraftCommand : IRequest<AircraftDto>
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;
|
||||||
|
|
||||||
|
public class AddAircraftCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<AddAircraftCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public AddAircraftCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(AddAircraftCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;
|
||||||
|
|
||||||
|
public class AddAircraftCommandHandler :
|
||||||
|
IRequestHandler<AddAircraftCommand, AircraftDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public AddAircraftCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AircraftDto> Handle(
|
||||||
|
AddAircraftCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.AircraftRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number, cancellationToken);
|
||||||
|
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Aircraft with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity = new Aircraft()
|
||||||
|
{
|
||||||
|
Number = request.Number,
|
||||||
|
Model = request.Model,
|
||||||
|
Capacity = request.Capacity
|
||||||
|
};
|
||||||
|
|
||||||
|
entity = await _unitOfWork.AircraftRepository.AddOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<AircraftDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;
|
||||||
|
|
||||||
|
public class AddAircraftCommandValidator : AbstractValidator<AddAircraftCommand>
|
||||||
|
{
|
||||||
|
public AddAircraftCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;
|
||||||
|
|
||||||
|
public record DeleteAircraftCommand : IRequest
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;
|
||||||
|
|
||||||
|
public class DeleteAircraftCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<DeleteAircraftCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public DeleteAircraftCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(DeleteAircraftCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;
|
||||||
|
|
||||||
|
public class DeleteAircraftCommandHandler : IRequestHandler<DeleteAircraftCommand>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
|
||||||
|
public DeleteAircraftCommandHandler(UnitOfWork unitOfWork)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(
|
||||||
|
DeleteAircraftCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.AircraftRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.AircraftRepository.DeleteOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;
|
||||||
|
|
||||||
|
public class DeleteAircraftCommandValidator : AbstractValidator<DeleteAircraftCommand>
|
||||||
|
{
|
||||||
|
public DeleteAircraftCommandValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;
|
||||||
|
|
||||||
|
public record UpdateAircraftCommand : IRequest<AircraftDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;
|
||||||
|
|
||||||
|
public class UpdateAircraftCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<UpdateAircraftCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public UpdateAircraftCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(UpdateAircraftCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;
|
||||||
|
|
||||||
|
public class UpdateAircraftCommandHandler :
|
||||||
|
IRequestHandler<UpdateAircraftCommand, AircraftDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public UpdateAircraftCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AircraftDto> Handle(
|
||||||
|
UpdateAircraftCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.AircraftRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicateEntity = await _unitOfWork.AircraftRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (duplicateEntity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Aircraft with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Number = request.Number;
|
||||||
|
entity.Model = request.Model;
|
||||||
|
entity.Capacity = request.Capacity;
|
||||||
|
|
||||||
|
entity = await _unitOfWork.AircraftRepository.UpdateOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<AircraftDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;
|
||||||
|
|
||||||
|
public class UpdateAircraftCommandValidator : AbstractValidator<UpdateAircraftCommand>
|
||||||
|
{
|
||||||
|
public UpdateAircraftCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;
|
||||||
|
|
||||||
|
public record GetAircraftQuery : IRequest<AircraftDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;
|
||||||
|
|
||||||
|
public class GetAircraftQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetAircraftQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetAircraftQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetAircraftQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;
|
||||||
|
|
||||||
|
public class GetAircraftQueryHandler :
|
||||||
|
IRequestHandler<GetAircraftQuery, AircraftDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetAircraftQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AircraftDto> Handle(
|
||||||
|
GetAircraftQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.AircraftRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mapper.Map<AircraftDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;
|
||||||
|
|
||||||
|
public class GetAircraftQueryValidator : AbstractValidator<GetAircraftQuery>
|
||||||
|
{
|
||||||
|
public GetAircraftQueryValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;
|
||||||
|
|
||||||
|
public record GetAircraftsPageQuery : IRequest<PaginatedList<AircraftDto>>
|
||||||
|
{
|
||||||
|
public int PageNumber { get; set; } = 1;
|
||||||
|
|
||||||
|
public int PageSize { get; set; } = 10;
|
||||||
|
|
||||||
|
public string Search { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string Sort { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;
|
||||||
|
|
||||||
|
public class GetAircraftsPageQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetAircraftsPageQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetAircraftsPageQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetAircraftsPageQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Extensions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;
|
||||||
|
|
||||||
|
public class GetAircraftsPageQueryHandler :
|
||||||
|
IRequestHandler<GetAircraftsPageQuery, PaginatedList<AircraftDto>>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetAircraftsPageQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PaginatedList<AircraftDto>> Handle(
|
||||||
|
GetAircraftsPageQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var paginatedList = await _unitOfWork.AircraftRepository.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
(e.Number.ToLower().Contains(request.Search.ToLower()) ||
|
||||||
|
e.Model.ToLower().Contains(request.Search.ToLower())) &&
|
||||||
|
(request.CapacityGreaterOrEqualThan != null
|
||||||
|
? e.Capacity >= request.CapacityGreaterOrEqualThan
|
||||||
|
: true) &&
|
||||||
|
(request.CapacityLessOrEqualThan != null
|
||||||
|
? e.Capacity <= request.CapacityLessOrEqualThan
|
||||||
|
: true),
|
||||||
|
request.PageNumber, request.PageSize,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var mappedItems = _mapper
|
||||||
|
.ProjectTo<AircraftDto>(paginatedList.Items.AsQueryable());
|
||||||
|
|
||||||
|
mappedItems = QueryableExtension<AircraftDto>
|
||||||
|
.ApplySort(mappedItems, request.Sort);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return new PaginatedList<AircraftDto>(
|
||||||
|
mappedItems.ToList(),
|
||||||
|
paginatedList.TotalCount, request.PageNumber,
|
||||||
|
request.PageSize);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;
|
||||||
|
|
||||||
|
public class GetAircraftsPageQueryValidator : AbstractValidator<GetAircraftsPageQuery>
|
||||||
|
{
|
||||||
|
public GetAircraftsPageQueryValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.PageNumber)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1));
|
||||||
|
|
||||||
|
RuleFor(v => v.PageSize)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1))
|
||||||
|
.LessThanOrEqualTo(50)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.LessThanOrEqualTo"],
|
||||||
|
50));
|
||||||
|
|
||||||
|
RuleFor(v => v.Search)
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
}
|
||||||
|
}
|
10
src/Application/Aircrafts/ViewModels/AddAircraftViewModel.cs
Normal file
10
src/Application/Aircrafts/ViewModels/AddAircraftViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.ViewModels;
|
||||||
|
|
||||||
|
public sealed class AddAircraftViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.ViewModels;
|
||||||
|
|
||||||
|
public sealed class GetAircraftsPageFilterViewModel
|
||||||
|
{
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
// TODO: Consider adding strict equals rule although it is not
|
||||||
|
// necessarily needed to filter with exact capacity
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Aircrafts.ViewModels;
|
||||||
|
|
||||||
|
public sealed class UpdateAircraftViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
23
src/Application/Buses/BusDto.cs
Normal file
23
src/Application/Buses/BusDto.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses;
|
||||||
|
|
||||||
|
public sealed class BusDto : IMapFrom<Bus>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<Bus, BusDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid));
|
||||||
|
}
|
||||||
|
}
|
12
src/Application/Buses/Commands/AddBus/AddBusCommand.cs
Normal file
12
src/Application/Buses/Commands/AddBus/AddBusCommand.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;
|
||||||
|
|
||||||
|
public record AddBusCommand : IRequest<BusDto>
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;
|
||||||
|
|
||||||
|
public class AddBusCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<AddBusCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public AddBusCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(AddBusCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;
|
||||||
|
|
||||||
|
public class AddBusCommandHandler :
|
||||||
|
IRequestHandler<AddBusCommand, BusDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public AddBusCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<BusDto> Handle(
|
||||||
|
AddBusCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.BusRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number, cancellationToken);
|
||||||
|
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Bus with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity = new Bus()
|
||||||
|
{
|
||||||
|
Number = request.Number,
|
||||||
|
Model = request.Model,
|
||||||
|
Capacity = request.Capacity
|
||||||
|
};
|
||||||
|
|
||||||
|
entity = await _unitOfWork.BusRepository.AddOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<BusDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;
|
||||||
|
|
||||||
|
public class AddBusCommandValidator : AbstractValidator<AddBusCommand>
|
||||||
|
{
|
||||||
|
public AddBusCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;
|
||||||
|
|
||||||
|
public record DeleteBusCommand : IRequest
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;
|
||||||
|
|
||||||
|
public class DeleteBusCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<DeleteBusCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public DeleteBusCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(DeleteBusCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;
|
||||||
|
|
||||||
|
public class DeleteBusCommandHandler : IRequestHandler<DeleteBusCommand>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
|
||||||
|
public DeleteBusCommandHandler(UnitOfWork unitOfWork)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(
|
||||||
|
DeleteBusCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.BusRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.BusRepository.DeleteOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;
|
||||||
|
|
||||||
|
public class DeleteBusCommandValidator : AbstractValidator<DeleteBusCommand>
|
||||||
|
{
|
||||||
|
public DeleteBusCommandValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
14
src/Application/Buses/Commands/UpdateBus/UpdateBusCommand.cs
Normal file
14
src/Application/Buses/Commands/UpdateBus/UpdateBusCommand.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;
|
||||||
|
|
||||||
|
public record UpdateBusCommand : IRequest<BusDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;
|
||||||
|
|
||||||
|
public class UpdateBusCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<UpdateBusCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public UpdateBusCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(UpdateBusCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;
|
||||||
|
|
||||||
|
public class UpdateBusCommandHandler :
|
||||||
|
IRequestHandler<UpdateBusCommand, BusDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public UpdateBusCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<BusDto> Handle(
|
||||||
|
UpdateBusCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.BusRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicateEntity = await _unitOfWork.BusRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (duplicateEntity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Bus with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Number = request.Number;
|
||||||
|
entity.Model = request.Model;
|
||||||
|
entity.Capacity = request.Capacity;
|
||||||
|
|
||||||
|
entity = await _unitOfWork.BusRepository.UpdateOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<BusDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;
|
||||||
|
|
||||||
|
public class UpdateBusCommandValidator : AbstractValidator<UpdateBusCommand>
|
||||||
|
{
|
||||||
|
public UpdateBusCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
8
src/Application/Buses/Queries/GetBus/GetBusQuery.cs
Normal file
8
src/Application/Buses/Queries/GetBus/GetBusQuery.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;
|
||||||
|
|
||||||
|
public record GetBusQuery : IRequest<BusDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;
|
||||||
|
|
||||||
|
public class GetBusQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetBusQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetBusQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetBusQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
38
src/Application/Buses/Queries/GetBus/GetBusQueryHandler.cs
Normal file
38
src/Application/Buses/Queries/GetBus/GetBusQueryHandler.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;
|
||||||
|
|
||||||
|
public class GetBusQueryHandler :
|
||||||
|
IRequestHandler<GetBusQuery, BusDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetBusQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<BusDto> Handle(
|
||||||
|
GetBusQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.BusRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mapper.Map<BusDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
14
src/Application/Buses/Queries/GetBus/GetBusQueryValidator.cs
Normal file
14
src/Application/Buses/Queries/GetBus/GetBusQueryValidator.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;
|
||||||
|
|
||||||
|
public class GetBusQueryValidator : AbstractValidator<GetBusQuery>
|
||||||
|
{
|
||||||
|
public GetBusQueryValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;
|
||||||
|
|
||||||
|
public record GetBusesPageQuery : IRequest<PaginatedList<BusDto>>
|
||||||
|
{
|
||||||
|
public int PageNumber { get; set; } = 1;
|
||||||
|
|
||||||
|
public int PageSize { get; set; } = 10;
|
||||||
|
|
||||||
|
public string Search { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string Sort { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;
|
||||||
|
|
||||||
|
public class GetBusesPageQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetBusesPageQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetBusesPageQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetBusesPageQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Extensions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;
|
||||||
|
|
||||||
|
public class GetBusesPageQueryHandler :
|
||||||
|
IRequestHandler<GetBusesPageQuery, PaginatedList<BusDto>>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetBusesPageQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PaginatedList<BusDto>> Handle(
|
||||||
|
GetBusesPageQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var paginatedList = await _unitOfWork.BusRepository.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
(e.Number.ToLower().Contains(request.Search.ToLower()) ||
|
||||||
|
e.Model.ToLower().Contains(request.Search.ToLower())) &&
|
||||||
|
(request.CapacityGreaterOrEqualThan != null
|
||||||
|
? e.Capacity >= request.CapacityGreaterOrEqualThan
|
||||||
|
: true) &&
|
||||||
|
(request.CapacityLessOrEqualThan != null
|
||||||
|
? e.Capacity <= request.CapacityLessOrEqualThan
|
||||||
|
: true),
|
||||||
|
request.PageNumber, request.PageSize,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var mappedItems = _mapper
|
||||||
|
.ProjectTo<BusDto>(paginatedList.Items.AsQueryable());
|
||||||
|
|
||||||
|
mappedItems = QueryableExtension<BusDto>
|
||||||
|
.ApplySort(mappedItems, request.Sort);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return new PaginatedList<BusDto>(
|
||||||
|
mappedItems.ToList(),
|
||||||
|
paginatedList.TotalCount, request.PageNumber,
|
||||||
|
request.PageSize);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;
|
||||||
|
|
||||||
|
public class GetBusesPageQueryValidator : AbstractValidator<GetBusesPageQuery>
|
||||||
|
{
|
||||||
|
public GetBusesPageQueryValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.PageNumber)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1));
|
||||||
|
|
||||||
|
RuleFor(v => v.PageSize)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1))
|
||||||
|
.LessThanOrEqualTo(50)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.LessThanOrEqualTo"],
|
||||||
|
50));
|
||||||
|
|
||||||
|
RuleFor(v => v.Search)
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
}
|
||||||
|
}
|
10
src/Application/Buses/ViewModels/AddBusViewModel.cs
Normal file
10
src/Application/Buses/ViewModels/AddBusViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.ViewModels;
|
||||||
|
|
||||||
|
public sealed class AddBusViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.ViewModels;
|
||||||
|
|
||||||
|
public sealed class GetBusesPageFilterViewModel
|
||||||
|
{
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
// TODO: Consider adding strict equals rule although it is not
|
||||||
|
// necessarily needed to filter with exact capacity
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
10
src/Application/Buses/ViewModels/UpdateBusViewModel.cs
Normal file
10
src/Application/Buses/ViewModels/UpdateBusViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Buses.ViewModels;
|
||||||
|
|
||||||
|
public sealed class UpdateBusViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface AircraftRepository : BaseRepository<Aircraft> { }
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface BusRepository : BaseRepository<Bus> { }
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface TrainRepository : BaseRepository<Train> { }
|
@ -0,0 +1,6 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces
|
||||||
|
.Persistence.Repositories;
|
||||||
|
|
||||||
|
public interface VehicleRepository : BaseRepository<Vehicle> { }
|
@ -14,6 +14,14 @@ public interface UnitOfWork : IDisposable
|
|||||||
|
|
||||||
RouteRepository RouteRepository { get; }
|
RouteRepository RouteRepository { get; }
|
||||||
|
|
||||||
|
VehicleRepository VehicleRepository { get; }
|
||||||
|
|
||||||
|
BusRepository BusRepository { get; }
|
||||||
|
|
||||||
|
AircraftRepository AircraftRepository { get; }
|
||||||
|
|
||||||
|
TrainRepository TrainRepository { get; }
|
||||||
|
|
||||||
int Save();
|
int Save();
|
||||||
|
|
||||||
Task<int> SaveAsync(CancellationToken cancellationToken);
|
Task<int> SaveAsync(CancellationToken cancellationToken);
|
||||||
|
12
src/Application/Trains/Commands/AddTrain/AddTrainCommand.cs
Normal file
12
src/Application/Trains/Commands/AddTrain/AddTrainCommand.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.AddTrain;
|
||||||
|
|
||||||
|
public record AddTrainCommand : IRequest<TrainDto>
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.AddTrain;
|
||||||
|
|
||||||
|
public class AddTrainCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<AddTrainCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public AddTrainCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(AddTrainCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.AddTrain;
|
||||||
|
|
||||||
|
public class AddTrainCommandHandler :
|
||||||
|
IRequestHandler<AddTrainCommand, TrainDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public AddTrainCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TrainDto> Handle(
|
||||||
|
AddTrainCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.TrainRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number, cancellationToken);
|
||||||
|
|
||||||
|
if (entity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Train with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity = new Train()
|
||||||
|
{
|
||||||
|
Number = request.Number,
|
||||||
|
Model = request.Model,
|
||||||
|
Capacity = request.Capacity
|
||||||
|
};
|
||||||
|
|
||||||
|
entity = await _unitOfWork.TrainRepository.AddOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<TrainDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.AddTrain;
|
||||||
|
|
||||||
|
public class AddTrainCommandValidator : AbstractValidator<AddTrainCommand>
|
||||||
|
{
|
||||||
|
public AddTrainCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.DeleteTrain;
|
||||||
|
|
||||||
|
public record DeleteTrainCommand : IRequest
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.DeleteTrain;
|
||||||
|
|
||||||
|
public class DeleteTrainCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<DeleteTrainCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public DeleteTrainCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(DeleteTrainCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.DeleteTrain;
|
||||||
|
|
||||||
|
public class DeleteTrainCommandHandler : IRequestHandler<DeleteTrainCommand>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
|
||||||
|
public DeleteTrainCommandHandler(UnitOfWork unitOfWork)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(
|
||||||
|
DeleteTrainCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.TrainRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.TrainRepository.DeleteOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.DeleteTrain;
|
||||||
|
|
||||||
|
public class DeleteTrainCommandValidator : AbstractValidator<DeleteTrainCommand>
|
||||||
|
{
|
||||||
|
public DeleteTrainCommandValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.UpdateTrain;
|
||||||
|
|
||||||
|
public record UpdateTrainCommand : IRequest<TrainDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.UpdateTrain;
|
||||||
|
|
||||||
|
public class UpdateTrainCommandAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<UpdateTrainCommand>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public UpdateTrainCommandAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(UpdateTrainCommand request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.UpdateTrain;
|
||||||
|
|
||||||
|
public class UpdateTrainCommandHandler :
|
||||||
|
IRequestHandler<UpdateTrainCommand, TrainDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public UpdateTrainCommandHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TrainDto> Handle(
|
||||||
|
UpdateTrainCommand request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.TrainRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicateEntity = await _unitOfWork.TrainRepository.GetOneAsync(
|
||||||
|
e => e.Number == request.Number,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
if (duplicateEntity != null)
|
||||||
|
{
|
||||||
|
throw new DuplicateEntityException(
|
||||||
|
"Train with given number already exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.Number = request.Number;
|
||||||
|
entity.Model = request.Model;
|
||||||
|
entity.Capacity = request.Capacity;
|
||||||
|
|
||||||
|
entity = await _unitOfWork.TrainRepository.UpdateOneAsync(
|
||||||
|
entity, cancellationToken);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return _mapper.Map<TrainDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Commands.UpdateTrain;
|
||||||
|
|
||||||
|
public class UpdateTrainCommandValidator : AbstractValidator<UpdateTrainCommand>
|
||||||
|
{
|
||||||
|
public UpdateTrainCommandValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
|
||||||
|
RuleFor(v => v.Number)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(32)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
32));
|
||||||
|
|
||||||
|
RuleFor(v => v.Model)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"])
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
|
||||||
|
RuleFor(v => v.Capacity)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
8
src/Application/Trains/Queries/GetTrain/GetTrainQuery.cs
Normal file
8
src/Application/Trains/Queries/GetTrain/GetTrainQuery.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrain;
|
||||||
|
|
||||||
|
public record GetTrainQuery : IRequest<TrainDto>
|
||||||
|
{
|
||||||
|
public Guid Guid { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrain;
|
||||||
|
|
||||||
|
public class GetTrainQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetTrainQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetTrainQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetTrainQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrain;
|
||||||
|
|
||||||
|
public class GetTrainQueryHandler :
|
||||||
|
IRequestHandler<GetTrainQuery, TrainDto>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetTrainQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TrainDto> Handle(
|
||||||
|
GetTrainQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await _unitOfWork.TrainRepository.GetOneAsync(
|
||||||
|
e => e.Guid == request.Guid, cancellationToken);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
if (entity == null)
|
||||||
|
{
|
||||||
|
throw new NotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mapper.Map<TrainDto>(entity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrain;
|
||||||
|
|
||||||
|
public class GetTrainQueryValidator : AbstractValidator<GetTrainQuery>
|
||||||
|
{
|
||||||
|
public GetTrainQueryValidator(IStringLocalizer localizer)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.Guid)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage(localizer["FluentValidation.NotEmpty"]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrainsPage;
|
||||||
|
|
||||||
|
public record GetTrainsPageQuery : IRequest<PaginatedList<TrainDto>>
|
||||||
|
{
|
||||||
|
public int PageNumber { get; set; } = 1;
|
||||||
|
|
||||||
|
public int PageSize { get; set; } = 10;
|
||||||
|
|
||||||
|
public string Search { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string Sort { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Authorization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using MediatR.Behaviors.Authorization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrainsPage;
|
||||||
|
|
||||||
|
public class GetTrainsPageQueryAuthorizer :
|
||||||
|
AbstractRequestAuthorizer<GetTrainsPageQuery>
|
||||||
|
{
|
||||||
|
private readonly SessionUserService _sessionUserService;
|
||||||
|
|
||||||
|
public GetTrainsPageQueryAuthorizer(SessionUserService sessionUserService)
|
||||||
|
{
|
||||||
|
_sessionUserService = sessionUserService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BuildPolicy(GetTrainsPageQuery request)
|
||||||
|
{
|
||||||
|
UseRequirement(new MustBeAuthenticatedRequirement
|
||||||
|
{
|
||||||
|
IsAuthenticated= _sessionUserService.IsAuthenticated
|
||||||
|
});
|
||||||
|
|
||||||
|
UseRequirement(new MustBeInRolesRequirement
|
||||||
|
{
|
||||||
|
RequiredRoles = [IdentityRole.Administrator],
|
||||||
|
UserRoles = _sessionUserService.Roles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using MediatR;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Extensions;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrainsPage;
|
||||||
|
|
||||||
|
public class GetTrainsPageQueryHandler :
|
||||||
|
IRequestHandler<GetTrainsPageQuery, PaginatedList<TrainDto>>
|
||||||
|
{
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GetTrainsPageQueryHandler(
|
||||||
|
UnitOfWork unitOfWork,
|
||||||
|
IMapper mapper)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PaginatedList<TrainDto>> Handle(
|
||||||
|
GetTrainsPageQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var paginatedList = await _unitOfWork.TrainRepository.GetPageAsync(
|
||||||
|
e =>
|
||||||
|
(e.Number.ToLower().Contains(request.Search.ToLower()) ||
|
||||||
|
e.Model.ToLower().Contains(request.Search.ToLower())) &&
|
||||||
|
(request.CapacityGreaterOrEqualThan != null
|
||||||
|
? e.Capacity >= request.CapacityGreaterOrEqualThan
|
||||||
|
: true) &&
|
||||||
|
(request.CapacityLessOrEqualThan != null
|
||||||
|
? e.Capacity <= request.CapacityLessOrEqualThan
|
||||||
|
: true),
|
||||||
|
request.PageNumber, request.PageSize,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var mappedItems = _mapper
|
||||||
|
.ProjectTo<TrainDto>(paginatedList.Items.AsQueryable());
|
||||||
|
|
||||||
|
mappedItems = QueryableExtension<TrainDto>
|
||||||
|
.ApplySort(mappedItems, request.Sort);
|
||||||
|
|
||||||
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
|
return new PaginatedList<TrainDto>(
|
||||||
|
mappedItems.ToList(),
|
||||||
|
paginatedList.TotalCount, request.PageNumber,
|
||||||
|
request.PageSize);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.Queries.GetTrainsPage;
|
||||||
|
|
||||||
|
public class GetTrainsPageQueryValidator : AbstractValidator<GetTrainsPageQuery>
|
||||||
|
{
|
||||||
|
public GetTrainsPageQueryValidator(
|
||||||
|
IStringLocalizer localizer,
|
||||||
|
CultureService cultureService)
|
||||||
|
{
|
||||||
|
RuleFor(v => v.PageNumber)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1));
|
||||||
|
|
||||||
|
RuleFor(v => v.PageSize)
|
||||||
|
.GreaterThanOrEqualTo(1)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.GreaterThanOrEqualTo"],
|
||||||
|
1))
|
||||||
|
.LessThanOrEqualTo(50)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.LessThanOrEqualTo"],
|
||||||
|
50));
|
||||||
|
|
||||||
|
RuleFor(v => v.Search)
|
||||||
|
.MaximumLength(64)
|
||||||
|
.WithMessage(
|
||||||
|
String.Format(
|
||||||
|
cultureService.Culture,
|
||||||
|
localizer["FluentValidation.MaximumLength"],
|
||||||
|
64));
|
||||||
|
}
|
||||||
|
}
|
23
src/Application/Trains/TrainDto.cs
Normal file
23
src/Application/Trains/TrainDto.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Mappings;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Trains;
|
||||||
|
|
||||||
|
public sealed class TrainDto : IMapFrom<Train>
|
||||||
|
{
|
||||||
|
public Guid Uuid { get; set; }
|
||||||
|
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
public void Mapping(MappingProfile profile)
|
||||||
|
{
|
||||||
|
profile.CreateMap<Train, TrainDto>()
|
||||||
|
.ForMember(
|
||||||
|
d => d.Uuid,
|
||||||
|
opt => opt.MapFrom(s => s.Guid));
|
||||||
|
}
|
||||||
|
}
|
10
src/Application/Trains/ViewModels/AddTrainViewModel.cs
Normal file
10
src/Application/Trains/ViewModels/AddTrainViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.ViewModels;
|
||||||
|
|
||||||
|
public sealed class AddTrainViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.ViewModels;
|
||||||
|
|
||||||
|
public sealed class GetTrainsPageFilterViewModel
|
||||||
|
{
|
||||||
|
public string? Number { get; set; }
|
||||||
|
|
||||||
|
public string? Model { get; set; }
|
||||||
|
|
||||||
|
// TODO: Consider adding strict equals rule although it is not
|
||||||
|
// necessarily needed to filter with exact capacity
|
||||||
|
|
||||||
|
public short? CapacityGreaterOrEqualThan { get; set; }
|
||||||
|
|
||||||
|
public short? CapacityLessOrEqualThan { get; set; }
|
||||||
|
}
|
10
src/Application/Trains/ViewModels/UpdateTrainViewModel.cs
Normal file
10
src/Application/Trains/ViewModels/UpdateTrainViewModel.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Application.Trains.ViewModels;
|
||||||
|
|
||||||
|
public sealed class UpdateTrainViewModel
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
}
|
@ -29,6 +29,7 @@ public static class Configuration
|
|||||||
configuration.ConnectionString,
|
configuration.ConnectionString,
|
||||||
options =>
|
options =>
|
||||||
{
|
{
|
||||||
|
// TODO: Move to persistence project
|
||||||
options.MigrationsHistoryTable(
|
options.MigrationsHistoryTable(
|
||||||
"ef_migrations_history",
|
"ef_migrations_history",
|
||||||
configuration.PartitionName);
|
configuration.PartitionName);
|
||||||
|
12
src/Domain/Entities/Aircraft.cs
Normal file
12
src/Domain/Entities/Aircraft.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public class Aircraft : Vehicle
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
// TODO: Add more properties to describe aircraft's capabilities
|
||||||
|
}
|
12
src/Domain/Entities/Bus.cs
Normal file
12
src/Domain/Entities/Bus.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public class Bus : Vehicle
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
// TODO: Add more properties to describe bus' capabilities
|
||||||
|
}
|
12
src/Domain/Entities/Train.cs
Normal file
12
src/Domain/Entities/Train.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public class Train : Vehicle
|
||||||
|
{
|
||||||
|
public string Number { get; set; }
|
||||||
|
|
||||||
|
public string Model { get; set; }
|
||||||
|
|
||||||
|
public short Capacity { get; set; }
|
||||||
|
|
||||||
|
// TODO: Add more properties to describe train's capabilities
|
||||||
|
}
|
8
src/Domain/Entities/Vehicle.cs
Normal file
8
src/Domain/Entities/Vehicle.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
public abstract class Vehicle : EntityBase
|
||||||
|
{
|
||||||
|
public VehicleType VehicleType { get; set; }
|
||||||
|
}
|
193
src/HttpApi/Controllers/AircraftsController.cs
Normal file
193
src/HttpApi/Controllers/AircraftsController.cs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.ViewModels;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.Commands.AddAircraft;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraftsPage;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.Queries.GetAircraft;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.Commands.UpdateAircraft;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.Commands.DeleteAircraft;
|
||||||
|
using cuqmbr.TravelGuide.Application.Aircrafts.ViewModels;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
||||||
|
|
||||||
|
[Route("aircrafts")]
|
||||||
|
public class AircraftsController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
[SwaggerOperation("Add a aircraft")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status201Created, "Object successfuly created",
|
||||||
|
typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<ActionResult<AircraftDto>> Add(
|
||||||
|
[FromBody] AddAircraftViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return StatusCode(
|
||||||
|
StatusCodes.Status201Created,
|
||||||
|
await Mediator.Send(
|
||||||
|
new AddAircraftCommand()
|
||||||
|
{
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[SwaggerOperation("Get a list of all aircrafts")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful",
|
||||||
|
typeof(PaginatedList<AircraftDto>))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<PaginatedList<AircraftDto>> GetPage(
|
||||||
|
[FromQuery] PageQuery pageQuery, [FromQuery] SearchQuery searchQuery,
|
||||||
|
[FromQuery] SortQuery sortQuery,
|
||||||
|
[FromQuery] GetAircraftsPageFilterViewModel filterQuery,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new GetAircraftsPageQuery()
|
||||||
|
{
|
||||||
|
PageNumber = pageQuery.PageNumber,
|
||||||
|
PageSize = pageQuery.PageSize,
|
||||||
|
Search = searchQuery.Search,
|
||||||
|
Sort = sortQuery.Sort,
|
||||||
|
CapacityGreaterOrEqualThan =
|
||||||
|
filterQuery.CapacityGreaterOrEqualThan,
|
||||||
|
CapacityLessOrEqualThan =
|
||||||
|
filterQuery.CapacityLessOrEqualThan
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Get a aircraft by uuid")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<AircraftDto> Get(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(new GetAircraftQuery() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Update a aircraft")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<AircraftDto> Update(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
[FromBody] UpdateAircraftViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new UpdateAircraftCommand()
|
||||||
|
{
|
||||||
|
Guid = uuid,
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Delete a aircraft")]
|
||||||
|
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(AircraftDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<IActionResult> Delete(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await Mediator.Send(
|
||||||
|
new DeleteAircraftCommand() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
return StatusCode(StatusCodes.Status204NoContent);
|
||||||
|
}
|
||||||
|
}
|
193
src/HttpApi/Controllers/BusesController.cs
Normal file
193
src/HttpApi/Controllers/BusesController.cs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.ViewModels;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.Commands.AddBus;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.Queries.GetBusesPage;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.Queries.GetBus;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.Commands.UpdateBus;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.Commands.DeleteBus;
|
||||||
|
using cuqmbr.TravelGuide.Application.Buses.ViewModels;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
||||||
|
|
||||||
|
[Route("buses")]
|
||||||
|
public class BusesController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
[SwaggerOperation("Add a bus")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status201Created, "Object successfuly created",
|
||||||
|
typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<ActionResult<BusDto>> Add(
|
||||||
|
[FromBody] AddBusViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return StatusCode(
|
||||||
|
StatusCodes.Status201Created,
|
||||||
|
await Mediator.Send(
|
||||||
|
new AddBusCommand()
|
||||||
|
{
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[SwaggerOperation("Get a list of all buses")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful",
|
||||||
|
typeof(PaginatedList<BusDto>))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<PaginatedList<BusDto>> GetPage(
|
||||||
|
[FromQuery] PageQuery pageQuery, [FromQuery] SearchQuery searchQuery,
|
||||||
|
[FromQuery] SortQuery sortQuery,
|
||||||
|
[FromQuery] GetBusesPageFilterViewModel filterQuery,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new GetBusesPageQuery()
|
||||||
|
{
|
||||||
|
PageNumber = pageQuery.PageNumber,
|
||||||
|
PageSize = pageQuery.PageSize,
|
||||||
|
Search = searchQuery.Search,
|
||||||
|
Sort = sortQuery.Sort,
|
||||||
|
CapacityGreaterOrEqualThan =
|
||||||
|
filterQuery.CapacityGreaterOrEqualThan,
|
||||||
|
CapacityLessOrEqualThan =
|
||||||
|
filterQuery.CapacityLessOrEqualThan
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Get a bus by uuid")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<BusDto> Get(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(new GetBusQuery() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Update a bus")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<BusDto> Update(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
[FromBody] UpdateBusViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new UpdateBusCommand()
|
||||||
|
{
|
||||||
|
Guid = uuid,
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Delete a bus")]
|
||||||
|
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(BusDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<IActionResult> Delete(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await Mediator.Send(
|
||||||
|
new DeleteBusCommand() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
return StatusCode(StatusCodes.Status204NoContent);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
|
|
||||||
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
||||||
|
|
||||||
@ -8,19 +9,41 @@ namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
|||||||
public class TestsController : ControllerBase
|
public class TestsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly IStringLocalizer _localizer;
|
private readonly IStringLocalizer _localizer;
|
||||||
|
private readonly UnitOfWork _unitOfWork;
|
||||||
|
|
||||||
public TestsController(
|
public TestsController(
|
||||||
CultureService cultureService,
|
CultureService cultureService,
|
||||||
IStringLocalizer localizer)
|
IStringLocalizer localizer,
|
||||||
|
UnitOfWork unitOfWork)
|
||||||
{
|
{
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("getLocalizedString/{inputString}")]
|
[HttpGet("getLocalizedString/{inputString}")]
|
||||||
public Task<string> getLocalizedString(
|
public Task<string> GetLocalizedString(
|
||||||
[FromRoute] string inputString,
|
[FromRoute] string inputString,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Task.FromResult<string>(_localizer[inputString]);
|
return Task.FromResult<string>(_localizer[inputString]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("trigger")]
|
||||||
|
public async Task Trigger(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// await _unitOfWork.BusRepository.AddOneAsync(
|
||||||
|
// new Domain.Entities.Bus()
|
||||||
|
// {
|
||||||
|
// Number = "AB1234MK",
|
||||||
|
// Model = "This is a fancy bus model",
|
||||||
|
// Capacity = 40
|
||||||
|
// },
|
||||||
|
// cancellationToken);
|
||||||
|
//
|
||||||
|
// await _unitOfWork.SaveAsync(cancellationToken);
|
||||||
|
// _unitOfWork.Dispose();
|
||||||
|
|
||||||
|
var vehicles = await _unitOfWork.VehicleRepository
|
||||||
|
.GetPageAsync(1, 10, cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
193
src/HttpApi/Controllers/TrainsController.cs
Normal file
193
src/HttpApi/Controllers/TrainsController.cs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.ViewModels;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.Commands.AddTrain;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.Queries.GetTrainsPage;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.Queries.GetTrain;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.Commands.UpdateTrain;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.Commands.DeleteTrain;
|
||||||
|
using cuqmbr.TravelGuide.Application.Trains.ViewModels;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Controllers;
|
||||||
|
|
||||||
|
[Route("trains")]
|
||||||
|
public class TrainsController : ControllerBase
|
||||||
|
{
|
||||||
|
[HttpPost]
|
||||||
|
[SwaggerOperation("Add a train")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status201Created, "Object successfuly created",
|
||||||
|
typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<ActionResult<TrainDto>> Add(
|
||||||
|
[FromBody] AddTrainViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return StatusCode(
|
||||||
|
StatusCodes.Status201Created,
|
||||||
|
await Mediator.Send(
|
||||||
|
new AddTrainCommand()
|
||||||
|
{
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[SwaggerOperation("Get a list of all trains")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful",
|
||||||
|
typeof(PaginatedList<TrainDto>))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<PaginatedList<TrainDto>> GetPage(
|
||||||
|
[FromQuery] PageQuery pageQuery, [FromQuery] SearchQuery searchQuery,
|
||||||
|
[FromQuery] SortQuery sortQuery,
|
||||||
|
[FromQuery] GetTrainsPageFilterViewModel filterQuery,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new GetTrainsPageQuery()
|
||||||
|
{
|
||||||
|
PageNumber = pageQuery.PageNumber,
|
||||||
|
PageSize = pageQuery.PageSize,
|
||||||
|
Search = searchQuery.Search,
|
||||||
|
Sort = sortQuery.Sort,
|
||||||
|
CapacityGreaterOrEqualThan =
|
||||||
|
filterQuery.CapacityGreaterOrEqualThan,
|
||||||
|
CapacityLessOrEqualThan =
|
||||||
|
filterQuery.CapacityLessOrEqualThan
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Get a train by uuid")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<TrainDto> Get(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(new GetTrainQuery() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Update a train")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status200OK, "Request successful", typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Object already exists",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Parent object not found",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<TrainDto> Update(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
[FromBody] UpdateTrainViewModel viewModel,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await Mediator.Send(
|
||||||
|
new UpdateTrainCommand()
|
||||||
|
{
|
||||||
|
Guid = uuid,
|
||||||
|
Number = viewModel.Number,
|
||||||
|
Model = viewModel.Model,
|
||||||
|
Capacity = viewModel.Capacity
|
||||||
|
},
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{uuid:guid}")]
|
||||||
|
[SwaggerOperation("Delete a train")]
|
||||||
|
[SwaggerResponse(StatusCodes.Status204NoContent, "Request successful")]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status400BadRequest, "Input data validation error",
|
||||||
|
typeof(HttpValidationProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status401Unauthorized, "Unauthorized to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status403Forbidden,
|
||||||
|
"Not enough privileges to perform an action",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status404NotFound, "Object not found", typeof(TrainDto))]
|
||||||
|
[SwaggerResponse(
|
||||||
|
StatusCodes.Status500InternalServerError, "Internal server error",
|
||||||
|
typeof(ProblemDetails))]
|
||||||
|
public async Task<IActionResult> Delete(
|
||||||
|
[FromRoute] Guid uuid,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
await Mediator.Send(
|
||||||
|
new DeleteTrainCommand() { Guid = uuid },
|
||||||
|
cancellationToken);
|
||||||
|
return StatusCode(StatusCodes.Status204NoContent);
|
||||||
|
}
|
||||||
|
}
|
31
src/HttpApi/appsettings.json
Normal file
31
src/HttpApi/appsettings.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"Application": {
|
||||||
|
"Logging": {
|
||||||
|
"Type": "SimpleConsole",
|
||||||
|
"LogLevel": "Information",
|
||||||
|
"TimestampFormat": "yyyy-MM-ddTHH:mm:ss.fffK",
|
||||||
|
"UseUtcTimestamp": true
|
||||||
|
},
|
||||||
|
"Datastore": {
|
||||||
|
"Type": "postgresql",
|
||||||
|
"ConnectionString": "Host=127.0.0.1:5432;Database=travel_guide;Username=postgres;Password=0000;Include Error Detail=true"
|
||||||
|
},
|
||||||
|
"Localization": {
|
||||||
|
"DefaultCultureName": "en-US",
|
||||||
|
"CacheDuration": "00:30:00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Identity": {
|
||||||
|
"Datastore": {
|
||||||
|
"Type": "postgresql",
|
||||||
|
"ConnectionString": "Host=127.0.0.1:5432;Database=travel_guide;Username=postgres;Password=0000"
|
||||||
|
},
|
||||||
|
"JsonWebToken": {
|
||||||
|
"Issuer": "https://api.travel-guide.cuqmbr.xyz",
|
||||||
|
"Audience": "https://travel-guide.cuqmbr.xyz",
|
||||||
|
"IssuerSigningKey": "a2c98dec80787a4e85ffb5bcbc24f7e4cc014d8a4fe43e9520480a50759164bc",
|
||||||
|
"AccessTokenValidity": "24:00:00",
|
||||||
|
"RefreshTokenValidity": "72:00:00"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,10 @@ public sealed class InMemoryUnitOfWork : UnitOfWork
|
|||||||
CityRepository = new InMemoryCityRepository(_dbContext);
|
CityRepository = new InMemoryCityRepository(_dbContext);
|
||||||
AddressRepository = new InMemoryAddressRepository(_dbContext);
|
AddressRepository = new InMemoryAddressRepository(_dbContext);
|
||||||
RouteRepository = new InMemoryRouteRepository(_dbContext);
|
RouteRepository = new InMemoryRouteRepository(_dbContext);
|
||||||
|
VehicleRepository = new InMemoryVehicleRepository(_dbContext);
|
||||||
|
BusRepository = new InMemoryBusRepository(_dbContext);
|
||||||
|
AircraftRepository = new InMemoryAircraftRepository(_dbContext);
|
||||||
|
TrainRepository = new InMemoryTrainRepository(_dbContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CountryRepository CountryRepository { get; init; }
|
public CountryRepository CountryRepository { get; init; }
|
||||||
@ -30,6 +34,14 @@ public sealed class InMemoryUnitOfWork : UnitOfWork
|
|||||||
|
|
||||||
public RouteRepository RouteRepository { get; init; }
|
public RouteRepository RouteRepository { get; init; }
|
||||||
|
|
||||||
|
public VehicleRepository VehicleRepository { get; init; }
|
||||||
|
|
||||||
|
public BusRepository BusRepository { get; init; }
|
||||||
|
|
||||||
|
public AircraftRepository AircraftRepository { get; init; }
|
||||||
|
|
||||||
|
public TrainRepository TrainRepository { get; init; }
|
||||||
|
|
||||||
public int Save()
|
public int Save()
|
||||||
{
|
{
|
||||||
return _dbContext.SaveChanges();
|
return _dbContext.SaveChanges();
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryAircraftRepository :
|
||||||
|
InMemoryBaseRepository<Aircraft>, AircraftRepository
|
||||||
|
{
|
||||||
|
public InMemoryAircraftRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryBusRepository :
|
||||||
|
InMemoryBaseRepository<Bus>, BusRepository
|
||||||
|
{
|
||||||
|
public InMemoryBusRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryTrainRepository :
|
||||||
|
InMemoryBaseRepository<Train>, TrainRepository
|
||||||
|
{
|
||||||
|
public InMemoryTrainRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence.Repositories;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.InMemory.Repositories;
|
||||||
|
|
||||||
|
public sealed class InMemoryVehicleRepository :
|
||||||
|
InMemoryBaseRepository<Vehicle>, VehicleRepository
|
||||||
|
{
|
||||||
|
public InMemoryVehicleRepository(InMemoryDbContext dbContext)
|
||||||
|
: base(dbContext) { }
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class AircraftConfiguration : IEntityTypeConfiguration<Aircraft>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Aircraft> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.HasBaseType<Vehicle>();
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Number)
|
||||||
|
.HasColumnName("number")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Model)
|
||||||
|
.HasColumnName("model")
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Capacity)
|
||||||
|
.HasColumnName("capacity")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.IsRequired(true);
|
||||||
|
}
|
||||||
|
}
|
@ -9,23 +9,21 @@ public class BaseConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
|
|||||||
{
|
{
|
||||||
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
|
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
|
||||||
{
|
{
|
||||||
|
// Set table name for inherited types using type name
|
||||||
|
// instead of mapped table name
|
||||||
|
var tableName = builder.Metadata.GetTableName();
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.HasKey(b => b.Id)
|
.HasKey(b => b.Id)
|
||||||
.HasName($"pk_{builder.Metadata.GetTableName() ??
|
.HasName($"pk_{tableName}");
|
||||||
// Set primary key for inherited types using type name
|
|
||||||
// instead of mapped table name
|
|
||||||
builder.Metadata.ShortName().ToLower()}");
|
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.Property(b => b.Id)
|
.Property(b => b.Id)
|
||||||
.HasColumnName("id")
|
.HasColumnName("id")
|
||||||
.HasColumnType("bigint")
|
.HasColumnType("bigint")
|
||||||
.UseSequence(
|
.UseSequence(
|
||||||
$"{builder.Metadata.GetTableName() ??
|
$"{tableName}_" +
|
||||||
// Set sequence for inherited types using type name
|
$"{builder.Property(b => b.Id).Metadata.GetColumnName()}_" +
|
||||||
// instead of mapped table name
|
|
||||||
builder.Metadata.ShortName().ToLower()}_" +
|
|
||||||
$"{builder.Property(b => b.Id).Metadata.GetColumnName()}_" +
|
|
||||||
"sequence");
|
"sequence");
|
||||||
|
|
||||||
|
|
||||||
@ -39,10 +37,7 @@ public class BaseConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
|
|||||||
.HasAlternateKey(b => b.Guid)
|
.HasAlternateKey(b => b.Guid)
|
||||||
.HasName(
|
.HasName(
|
||||||
"altk_" +
|
"altk_" +
|
||||||
$"{builder.Metadata.GetTableName() ??
|
$"{tableName}_" +
|
||||||
// Set alternate key for inherited types using type name
|
|
||||||
// instead of mapped table name
|
|
||||||
builder.Metadata.ShortName().ToLower()}_" +
|
|
||||||
$"{builder.Property(b => b.Guid).Metadata.GetColumnName()}");
|
$"{builder.Property(b => b.Guid).Metadata.GetColumnName()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class BusConfiguration : IEntityTypeConfiguration<Bus>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Bus> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.HasBaseType<Vehicle>();
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Number)
|
||||||
|
.HasColumnName("number")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Model)
|
||||||
|
.HasColumnName("model")
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Capacity)
|
||||||
|
.HasColumnName("capacity")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.IsRequired(true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class TrainConfiguration : IEntityTypeConfiguration<Train>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<Train> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.HasBaseType<Vehicle>();
|
||||||
|
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Number)
|
||||||
|
.HasColumnName("number")
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Model)
|
||||||
|
.HasColumnName("model")
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Property(b => b.Capacity)
|
||||||
|
.HasColumnName("capacity")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.IsRequired(true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Entities;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Persistence.PostgreSql.Configurations;
|
||||||
|
|
||||||
|
public class VehicleConfiguration : BaseConfiguration<Vehicle>
|
||||||
|
{
|
||||||
|
public override void Configure(EntityTypeBuilder<Vehicle> builder)
|
||||||
|
{
|
||||||
|
builder
|
||||||
|
.Property(a => a.VehicleType)
|
||||||
|
.HasColumnName("vehicle_type")
|
||||||
|
.HasColumnType("varchar(16)")
|
||||||
|
.IsRequired(true);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ToTable(
|
||||||
|
"vehicles",
|
||||||
|
v => v.HasCheckConstraint(
|
||||||
|
"ck_" +
|
||||||
|
$"{builder.Metadata.GetTableName()}_" +
|
||||||
|
$"{builder.Property(v => v.VehicleType)
|
||||||
|
.Metadata.GetColumnName()}",
|
||||||
|
$"{builder.Property(v => v.VehicleType)
|
||||||
|
.Metadata.GetColumnName()} IN ('{String
|
||||||
|
.Join("', '", VehicleType.Enumerations
|
||||||
|
.Values.Select(v => v.Name))}')"));
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ToTable("vehicles")
|
||||||
|
.UseTphMappingStrategy()
|
||||||
|
.HasDiscriminator(v => v.VehicleType)
|
||||||
|
.HasValue<Bus>(VehicleType.Bus)
|
||||||
|
.HasValue<Aircraft>(VehicleType.Aircraft)
|
||||||
|
.HasValue<Train>(VehicleType.Train);
|
||||||
|
|
||||||
|
base.Configure(builder);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,476 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
using cuqmbr.TravelGuide.Persistence.PostgreSql;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.PostgreSql.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PostgreSqlDbContext))]
|
||||||
|
[Migration("20250503053607_Add_Bus_Aircraft_Train_with_basic_properties")]
|
||||||
|
partial class Add_Bus_Aircraft_Train_with_basic_properties
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasDefaultSchema("application")
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("addresses_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("cities_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("countries_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("regions_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("route_addresses_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("routes_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("vehicles_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.addresses_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "addresses_id_sequence");
|
||||||
|
|
||||||
|
b.Property<long>("CityId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("city_id");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<double>("Latitude")
|
||||||
|
.HasColumnType("double precision");
|
||||||
|
|
||||||
|
b.Property<double>("Longitude")
|
||||||
|
.HasColumnType("double precision");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(128)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<string>("VehicleType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(16)")
|
||||||
|
.HasColumnName("vehicle_type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_addresses");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_addresses_uuid");
|
||||||
|
|
||||||
|
b.HasIndex("CityId")
|
||||||
|
.HasDatabaseName("ix_addresses_city_id");
|
||||||
|
|
||||||
|
b.ToTable("addresses", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_addresses_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.cities_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "cities_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<long>("RegionId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("region_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_cities");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_cities_uuid");
|
||||||
|
|
||||||
|
b.HasIndex("RegionId")
|
||||||
|
.HasDatabaseName("ix_cities_region_id");
|
||||||
|
|
||||||
|
b.ToTable("cities", "application");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Country", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.countries_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "countries_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_countries");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_countries_uuid");
|
||||||
|
|
||||||
|
b.ToTable("countries", "application");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Region", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.regions_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "regions_id_sequence");
|
||||||
|
|
||||||
|
b.Property<long>("CountryId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("country_id");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_regions");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_regions_uuid");
|
||||||
|
|
||||||
|
b.HasIndex("CountryId")
|
||||||
|
.HasDatabaseName("ix_regions_country_id");
|
||||||
|
|
||||||
|
b.ToTable("regions", "application");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.routes_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "routes_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("name");
|
||||||
|
|
||||||
|
b.Property<string>("VehicleType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(16)")
|
||||||
|
.HasColumnName("vehicle_type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_routes");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_routes_uuid");
|
||||||
|
|
||||||
|
b.ToTable("routes", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_routes_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.route_addresses_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "route_addresses_id_sequence");
|
||||||
|
|
||||||
|
b.Property<long>("AddressId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("address_id");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<short>("Order")
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("order");
|
||||||
|
|
||||||
|
b.Property<long>("RouteId")
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("route_id");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_route_addresses");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_route_addresses_uuid");
|
||||||
|
|
||||||
|
b.HasAlternateKey("AddressId", "RouteId", "Order")
|
||||||
|
.HasName("altk_route_addresses_address_id_route_id_order");
|
||||||
|
|
||||||
|
b.HasIndex("AddressId")
|
||||||
|
.HasDatabaseName("ix_route_addresses_address_id");
|
||||||
|
|
||||||
|
b.HasIndex("RouteId")
|
||||||
|
.HasDatabaseName("ix_route_addresses_route_id");
|
||||||
|
|
||||||
|
b.ToTable("route_addresses", "application");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.vehicles_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "vehicles_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("VehicleType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(16)")
|
||||||
|
.HasColumnName("vehicle_type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_vehicles");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_vehicles_uuid");
|
||||||
|
|
||||||
|
b.ToTable("vehicles", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("VehicleType");
|
||||||
|
|
||||||
|
b.UseTphMappingStrategy();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Aircraft", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("aircraft");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Bus", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("bus");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Train", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("train");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City")
|
||||||
|
.WithMany("Addresses")
|
||||||
|
.HasForeignKey("CityId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_addresses_city_id");
|
||||||
|
|
||||||
|
b.Navigation("City");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Region", "Region")
|
||||||
|
.WithMany("Cities")
|
||||||
|
.HasForeignKey("RegionId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_cities_region_id");
|
||||||
|
|
||||||
|
b.Navigation("Region");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Region", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Country", "Country")
|
||||||
|
.WithMany("Regions")
|
||||||
|
.HasForeignKey("CountryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_regions_country_id");
|
||||||
|
|
||||||
|
b.Navigation("Country");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.RouteAddress", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Address", "Address")
|
||||||
|
.WithMany("AddressRoutes")
|
||||||
|
.HasForeignKey("AddressId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_route_addresses_address_id");
|
||||||
|
|
||||||
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.Route", "Route")
|
||||||
|
.WithMany("RouteAddresses")
|
||||||
|
.HasForeignKey("RouteId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired()
|
||||||
|
.HasConstraintName("fk_route_addresses_route_id");
|
||||||
|
|
||||||
|
b.Navigation("Address");
|
||||||
|
|
||||||
|
b.Navigation("Route");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("AddressRoutes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.City", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Addresses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Country", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Regions");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Region", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Cities");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Route", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("RouteAddresses");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Persistence.PostgreSql.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class Add_Bus_Aircraft_Train_with_basic_properties : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateSequence(
|
||||||
|
name: "vehicles_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "vehicles",
|
||||||
|
schema: "application",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<long>(type: "bigint", nullable: false, defaultValueSql: "nextval('application.vehicles_id_sequence')"),
|
||||||
|
vehicle_type = table.Column<string>(type: "varchar(16)", nullable: false),
|
||||||
|
number = table.Column<string>(type: "varchar(32)", nullable: true),
|
||||||
|
model = table.Column<string>(type: "varchar(64)", nullable: true),
|
||||||
|
capacity = table.Column<short>(type: "smallint", nullable: true),
|
||||||
|
uuid = table.Column<Guid>(type: "uuid", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_vehicles", x => x.id);
|
||||||
|
table.UniqueConstraint("altk_vehicles_uuid", x => x.uuid);
|
||||||
|
table.CheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "vehicles",
|
||||||
|
schema: "application");
|
||||||
|
|
||||||
|
migrationBuilder.DropSequence(
|
||||||
|
name: "vehicles_id_sequence",
|
||||||
|
schema: "application");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,8 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
|
|
||||||
modelBuilder.HasSequence("routes_id_sequence");
|
modelBuilder.HasSequence("routes_id_sequence");
|
||||||
|
|
||||||
|
modelBuilder.HasSequence("vehicles_id_sequence");
|
||||||
|
|
||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("Id")
|
b.Property<long>("Id")
|
||||||
@ -262,6 +264,128 @@ namespace Persistence.PostgreSql.Migrations
|
|||||||
b.ToTable("route_addresses", "application");
|
b.ToTable("route_addresses", "application");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Vehicle", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint")
|
||||||
|
.HasColumnName("id")
|
||||||
|
.HasDefaultValueSql("nextval('application.vehicles_id_sequence')");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseSequence(b.Property<long>("Id"), "vehicles_id_sequence");
|
||||||
|
|
||||||
|
b.Property<Guid>("Guid")
|
||||||
|
.HasColumnType("uuid")
|
||||||
|
.HasColumnName("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("VehicleType")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(16)")
|
||||||
|
.HasColumnName("vehicle_type");
|
||||||
|
|
||||||
|
b.HasKey("Id")
|
||||||
|
.HasName("pk_vehicles");
|
||||||
|
|
||||||
|
b.HasAlternateKey("Guid")
|
||||||
|
.HasName("altk_vehicles_uuid");
|
||||||
|
|
||||||
|
b.ToTable("vehicles", "application", t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("VehicleType");
|
||||||
|
|
||||||
|
b.UseTphMappingStrategy();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Aircraft", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("aircraft");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Bus", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("bus");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Train", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("cuqmbr.TravelGuide.Domain.Entities.Vehicle");
|
||||||
|
|
||||||
|
b.Property<short>("Capacity")
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("smallint")
|
||||||
|
.HasColumnName("capacity");
|
||||||
|
|
||||||
|
b.Property<string>("Model")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(64)")
|
||||||
|
.HasColumnName("model");
|
||||||
|
|
||||||
|
b.Property<string>("Number")
|
||||||
|
.IsRequired()
|
||||||
|
.ValueGeneratedOnUpdateSometimes()
|
||||||
|
.HasColumnType("varchar(32)")
|
||||||
|
.HasColumnName("number");
|
||||||
|
|
||||||
|
b.ToTable(t =>
|
||||||
|
{
|
||||||
|
t.HasCheckConstraint("ck_vehicles_vehicle_type", "vehicle_type IN ('bus', 'train', 'aircraft')");
|
||||||
|
});
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("train");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
modelBuilder.Entity("cuqmbr.TravelGuide.Domain.Entities.Address", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City")
|
b.HasOne("cuqmbr.TravelGuide.Domain.Entities.City", "City")
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user