add entity management functionality

This commit is contained in:
cuqmbr 2023-12-03 12:31:31 +02:00
parent ac6137a1ae
commit 806a139d3d
Signed by: cuqmbr
GPG Key ID: 2D72ED98B6CB200F
195 changed files with 7320 additions and 19 deletions

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Addresses.Commands.CreateAddress;
using AutobusApi.Application.Addresses.Commands.DeleteAddress;
using AutobusApi.Application.Addresses.Commands.UpdateAddress;
using AutobusApi.Application.Addresses.Queries;
using AutobusApi.Application.Addresses.Queries.GetAddressesWithPagination;
using AutobusApi.Application.Addresses.Queries.GetAddress;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("addresses")]
public class AddressController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateAddressCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<AddressDto>> GetPage([FromQuery] GetAddressesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<AddressDto> Get(int id, /* [FromQuery] GetAddressQuery query, */ CancellationToken cancellationToken)
{
var query = new GetAddressQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateAddressCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteAddressCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteAddressCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[ApiController]
[Route("[controller]")]
public class BaseController : ControllerBase
{
private IMediator _mediator;

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Buses.Commands.CreateBus;
using AutobusApi.Application.Buses.Commands.DeleteBus;
using AutobusApi.Application.Buses.Commands.UpdateBus;
using AutobusApi.Application.Buses.Queries;
using AutobusApi.Application.Buses.Queries.GetBusesWithPagination;
using AutobusApi.Application.Buses.Queries.GetBus;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("vehicle/buses")]
public class BusController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateBusCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<BusDto>> GetPage([FromQuery] GetBusesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<BusDto> Get(int id, /* [FromQuery] GetBusQuery query, */ CancellationToken cancellationToken)
{
var query = new GetBusQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateBusCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteBusCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteBusCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Cities.Commands.CreateCity;
using AutobusApi.Application.Cities.Commands.DeleteCity;
using AutobusApi.Application.Cities.Commands.UpdateCity;
using AutobusApi.Application.Cities.Queries;
using AutobusApi.Application.Cities.Queries.GetCitiesWithPagination;
using AutobusApi.Application.Cities.Queries.GetCity;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("cities")]
public class CityController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateCityCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<CityDto>> GetPage([FromQuery] GetCitiesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<CityDto> Get(int id, /* [FromQuery] GetCityQuery query, */ CancellationToken cancellationToken)
{
var query = new GetCityQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateCityCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteCityCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteCityCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Companies.Commands.CreateCompany;
using AutobusApi.Application.Companies.Commands.DeleteCompany;
using AutobusApi.Application.Companies.Commands.UpdateCompany;
using AutobusApi.Application.Companies.Queries;
using AutobusApi.Application.Companies.Queries.GetCompaniesWithPagination;
using AutobusApi.Application.Companies.Queries.GetCompany;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("companies")]
public class CompanyController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateCompanyCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<CompanyDto>> GetPage([FromQuery] GetCompaniesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<CompanyDto> Get(int id, /* [FromQuery] GetCompanyQuery query, */ CancellationToken cancellationToken)
{
var query = new GetCompanyQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateCompanyCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteCompanyCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteCompanyCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Countries.Commands.CreateCountry;
using AutobusApi.Application.Countries.Commands.DeleteCountry;
using AutobusApi.Application.Countries.Commands.UpdateCountry;
using AutobusApi.Application.Countries.Queries;
using AutobusApi.Application.Countries.Queries.GetCountriesWithPagination;
using AutobusApi.Application.Countries.Queries.GetCountry;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("countries")]
public class CountryController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateCountryCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<CountryDto>> GetPage([FromQuery] GetCountriesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<CountryDto> Get(int id, /* [FromQuery] GetCountryQuery query, */ CancellationToken cancellationToken)
{
var query = new GetCountryQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateCountryCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteCountryCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteCountryCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Employees.Commands.CreateEmployee;
using AutobusApi.Application.Employees.Commands.DeleteEmployee;
using AutobusApi.Application.Employees.Commands.UpdateEmployee;
using AutobusApi.Application.Employees.Queries;
using AutobusApi.Application.Employees.Queries.GetEmployeesWithPagination;
using AutobusApi.Application.Employees.Queries.GetEmployee;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("employees")]
public class EmployeeController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateEmployeeCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<EmployeeDto>> GetPage([FromQuery] GetEmployeesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<EmployeeDto> Get(int id, /* [FromQuery] GetEmployeeQuery query, */ CancellationToken cancellationToken)
{
var query = new GetEmployeeQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateEmployeeCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteEmployeeCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteEmployeeCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("identity")]
public class IdentityController : BaseController
{
[HttpPost("register")]

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Regions.Commands.CreateRegion;
using AutobusApi.Application.Regions.Commands.DeleteRegion;
using AutobusApi.Application.Regions.Commands.UpdateRegion;
using AutobusApi.Application.Regions.Queries;
using AutobusApi.Application.Regions.Queries.GetRegionsWithPagination;
using AutobusApi.Application.Regions.Queries.GetRegion;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("regions")]
public class RegionController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateRegionCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<RegionDto>> GetPage([FromQuery] GetRegionsWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<RegionDto> Get(int id, /* [FromQuery] GetRegionQuery query, */ CancellationToken cancellationToken)
{
var query = new GetRegionQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateRegionCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteRegionCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteRegionCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.Routes.Commands.CreateRoute;
using AutobusApi.Application.Routes.Commands.DeleteRoute;
using AutobusApi.Application.Routes.Commands.UpdateRoute;
using AutobusApi.Application.Routes.Queries;
using AutobusApi.Application.Routes.Queries.GetRoutesWithPagination;
using AutobusApi.Application.Routes.Queries.GetRoute;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("routes")]
public class RouteController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateRouteCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<RouteDto>> GetPage([FromQuery] GetRoutesWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<RouteDto> Get(int id, /* [FromQuery] GetRouteQuery query, */ CancellationToken cancellationToken)
{
var query = new GetRouteQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateRouteCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteRouteCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteRouteCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.TicketGroups.Commands.CreateTicketGroup;
using AutobusApi.Application.TicketGroups.Commands.DeleteTicketGroup;
using AutobusApi.Application.TicketGroups.Commands.UpdateTicketGroup;
using AutobusApi.Application.TicketGroups.Queries;
using AutobusApi.Application.TicketGroups.Queries.GetTicketGroupsWithPagination;
using AutobusApi.Application.TicketGroups.Queries.GetTicketGroup;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("ticketgroups")]
public class TicketGroupController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateTicketGroupCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<TicketGroupDto>> GetPage([FromQuery] GetTicketGroupsWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<TicketGroupDto> Get(int id, /* [FromQuery] GetTicketGroupQuery query, */ CancellationToken cancellationToken)
{
var query = new GetTicketGroupQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateTicketGroupCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteTicketGroupCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteTicketGroupCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -0,0 +1,46 @@
using AutobusApi.Application.Common.Models;
using AutobusApi.Application.VehicleEnrollments.Commands.CreateVehicleEnrollment;
using AutobusApi.Application.VehicleEnrollments.Commands.DeleteVehicleEnrollment;
using AutobusApi.Application.VehicleEnrollments.Commands.UpdateVehicleEnrollment;
using AutobusApi.Application.VehicleEnrollments.Queries;
using AutobusApi.Application.VehicleEnrollments.Queries.GetVehicleEnrollmentsWithPagination;
using AutobusApi.Application.VehicleEnrollments.Queries.GetVehicleEnrollment;
using Microsoft.AspNetCore.Mvc;
namespace AutobusApi.Api.Controllers;
[Route("vehicleenrollments")]
public class VehicleEnrollmentController : BaseController
{
[HttpPost]
public async Task<int> Create([FromBody] CreateVehicleEnrollmentCommand command, CancellationToken cancellationToken)
{
return await Mediator.Send(command, cancellationToken);
}
[HttpGet]
public async Task<PaginatedList<VehicleEnrollmentDto>> GetPage([FromQuery] GetVehicleEnrollmentsWithPaginationQuery query, CancellationToken cancellationToken)
{
return await Mediator.Send(query, cancellationToken);
}
[HttpGet("{id}")]
public async Task<VehicleEnrollmentDto> Get(int id, /* [FromQuery] GetVehicleEnrollmentQuery query, */ CancellationToken cancellationToken)
{
var query = new GetVehicleEnrollmentQuery() { Id = id };
return await Mediator.Send(query, cancellationToken);
}
[HttpPut]
public async Task Update([FromBody] UpdateVehicleEnrollmentCommand command, CancellationToken cancellationToken)
{
await Mediator.Send(command, cancellationToken);
}
[HttpDelete("{id}")]
public async Task Delete(int id, /* [FromBody] DeleteVehicleEnrollmentCommand command, */ CancellationToken cancellationToken)
{
var command = new DeleteVehicleEnrollmentCommand() { Id = id };
await Mediator.Send(command, cancellationToken);
}
}

View File

@ -124,6 +124,7 @@ public class GlobalExceptionHandlerMiddleware : IMiddleware
Detail = "Report this error to service's support team.",
});
await Console.Error.WriteLineAsync(exception.Message);
await Console.Error.WriteLineAsync(exception.StackTrace);
}
}

View File

@ -1,6 +1,6 @@
{
"ConnectionStrings": {
"DefaultConnection": "Host=10.0.0.20:5432;Database=autobus;Username=postgres;Password=12345678"
"DefaultConnection": "Host=10.0.1.20:5432;Database=autobus;Username=postgres;Password=12345678"
},
"Jwt": {
"Issuer": "",

View File

@ -0,0 +1,16 @@
using MediatR;
namespace AutobusApi.Application.Addresses.Commands.CreateAddress;
public record CreateAddressCommand : IRequest<int>
{
public string Name { get; set; } = null!;
public int CityId { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public string VehicleType { get; set; } = null!;
}

View File

@ -0,0 +1,36 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Entities;
using AutobusApi.Domain.Enums;
using MediatR;
namespace AutobusApi.Application.Addresses.Commands.CreateAddress;
public class CreateAddressCommandHandler : IRequestHandler<CreateAddressCommand, int>
{
private readonly IApplicationDbContext _dbContext;
public CreateAddressCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> Handle(
CreateAddressCommand request,
CancellationToken cancellationToken)
{
var address = new Address();
address.Name = request.Name;
address.CityId = request.CityId;
// TODO: Fix abstraction problems
// address.Location.Latitude = request.Latitude;
// address.Location.Longitude = request.Longitude;
address.VehicleType = Enum.Parse<VehicleType>(request.VehicleType);
_dbContext.Addresses.Add(address);
await _dbContext.SaveChangesAsync(cancellationToken);
return address.Id;
}
}

View File

@ -0,0 +1,20 @@
using AutobusApi.Domain.Enums;
using FluentValidation;
namespace AutobusApi.Application.Addresses.Commands.CreateAddress;
public class CreateAddressCommandValidator : AbstractValidator<CreateAddressCommand>
{
public CreateAddressCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.CityId).GreaterThan(0);
RuleFor(v => v.Latitude).GreaterThanOrEqualTo(-180).LessThanOrEqualTo(180);
RuleFor(v => v.Longitude).GreaterThanOrEqualTo(-180).LessThanOrEqualTo(180);
RuleFor(v => v.VehicleType).Must(value => Enum.TryParse<VehicleType>(value, true, out _));
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Addresses.Commands.DeleteAddress;
public record DeleteAddressCommand : IRequest
{
public int Id { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Addresses.Commands.DeleteAddress;
public class DeleteAddressCommandHandler : IRequestHandler<DeleteAddressCommand>
{
private readonly IApplicationDbContext _dbContext;
public DeleteAddressCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
DeleteAddressCommand request,
CancellationToken cancellationToken)
{
var address = await _dbContext.Addresses
.SingleOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (address == null)
{
throw new NotFoundException();
}
_dbContext.Addresses.Remove(address);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Addresses.Commands.DeleteAddress;
public class DeleteAddressCommandValidator : AbstractValidator<DeleteAddressCommand>
{
public DeleteAddressCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,18 @@
using MediatR;
namespace AutobusApi.Application.Addresses.Commands.UpdateAddress;
public record UpdateAddressCommand : IRequest
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public int CityId { get; set; }
public double Latitude { get; set; }
public double Longitude { get; set; }
public string VehicleType { get; set; } = null!;
}

View File

@ -0,0 +1,38 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Enums;
using MediatR;
namespace AutobusApi.Application.Addresses.Commands.UpdateAddress;
public class UpdateAddressCommandHandler : IRequestHandler<UpdateAddressCommand>
{
private readonly IApplicationDbContext _dbContext;
public UpdateAddressCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
UpdateAddressCommand request,
CancellationToken cancellationToken)
{
var address = await _dbContext.Addresses
.FindAsync(new object[] { request.Id }, cancellationToken);
if (address == null)
{
throw new NotFoundException();
}
address.Name = request.Name;
address.CityId = request.CityId;
// TODO: Fix abstraction problems
// address.Location.Latitude = request.Latitude;
// address.Location.Longitude = request.Longitude;
address.VehicleType = Enum.Parse<VehicleType>(request.VehicleType);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,22 @@
using AutobusApi.Domain.Enums;
using FluentValidation;
namespace AutobusApi.Application.Addresses.Commands.UpdateAddress;
public class UpdateAddressCommandValidator : AbstractValidator<UpdateAddressCommand>
{
public UpdateAddressCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.Id).GreaterThan(0);
RuleFor(v => v.CityId).GreaterThan(0);
RuleFor(v => v.Latitude).GreaterThanOrEqualTo(-180).LessThanOrEqualTo(180);
RuleFor(v => v.Longitude).GreaterThanOrEqualTo(-180).LessThanOrEqualTo(180);
RuleFor(v => v.VehicleType).Must(value => Enum.TryParse<VehicleType>(value, true, out _));
}
}

View File

@ -0,0 +1,44 @@
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Domain.Entities;
using AutoMapper;
namespace AutobusApi.Application.Addresses.Queries;
public class AddressDto : IMapFrom<Address>
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public double Latitude { get; set; }
public double Longitude { get; set; }
public string VehicleType { get; set; } = null!;
public int CityId { get; set; }
public string CityName { get; set; } = null!;
public int RegionId { get; set; }
public string RegionName { get; set; } = null!;
public int CountryId { get; set; }
public string CountryName { get; set; } = null!;
public void Mapping(Profile profile)
{
profile.CreateMap<Address, AddressDto>()
.ForMember(d => d.CityId, opt => opt.MapFrom(s => s.CityId))
.ForMember(d => d.CityName, opt => opt.MapFrom(s => s.City.Name))
.ForMember(d => d.RegionId, opt => opt.MapFrom(s => s.City.RegionId))
.ForMember(d => d.RegionName, opt => opt.MapFrom(s => s.City.Region.Name))
.ForMember(d => d.CountryId, opt => opt.MapFrom(s => s.City.Region.CountryId))
.ForMember(d => d.CountryName, opt => opt.MapFrom(s => s.City.Region.Country.Name))
.ForMember(d => d.Latitude, opt => opt.MapFrom(s => s.Location.Latitude))
.ForMember(d => d.Longitude, opt => opt.MapFrom(s => s.Location.Longitude))
.ForMember(d => d.VehicleType, opt => opt.MapFrom(s => s.VehicleType.ToString()));
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Addresses.Queries.GetAddress;
public record GetAddressQuery : IRequest<AddressDto>
{
public int Id { get; set; }
}

View File

@ -0,0 +1,36 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutoMapper;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Addresses.Queries.GetAddress;
public class GetAddressQueryHandler : IRequestHandler<GetAddressQuery, AddressDto>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetAddressQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<AddressDto> Handle(
GetAddressQuery request,
CancellationToken cancellationToken)
{
var address = await _dbContext.Addresses
.SingleOrDefaultAsync(c => c.Id == request.Id);
if (address == null)
{
throw new NotFoundException();
}
return _mapper.Map<AddressDto>(address);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Addresses.Queries.GetAddress;
public class GetAddressQueryValidator : AbstractValidator<GetAddressQuery>
{
public GetAddressQueryValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,13 @@
using AutobusApi.Application.Common.Models;
using MediatR;
namespace AutobusApi.Application.Addresses.Queries.GetAddressesWithPagination;
public record GetAddressesWithPaginationQuery : IRequest<PaginatedList<AddressDto>>
{
public string Sort { get; set; } = "";
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
namespace AutobusApi.Application.Addresses.Queries.GetAddressesWithPagination;
public class GetAddressesWithPaginationQueryHandler : IRequestHandler<GetAddressesWithPaginationQuery, PaginatedList<AddressDto>>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetAddressesWithPaginationQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<PaginatedList<AddressDto>> Handle(
GetAddressesWithPaginationQuery request,
CancellationToken cancellationToken)
{
return await _dbContext.Addresses
.ProjectTo<AddressDto>(_mapper.ConfigurationProvider)
.ApplySort(request.Sort)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Addresses.Queries.GetAddressesWithPagination;
public class GetAddressesWithPaginationQueryValidator : AbstractValidator<GetAddressesWithPaginationQuery>
{
public GetAddressesWithPaginationQueryValidator()
{
RuleFor(v => v.PageNumber).GreaterThanOrEqualTo(1);
RuleFor(v => v.PageSize).GreaterThanOrEqualTo(1).LessThanOrEqualTo(50);
}
}

View File

@ -18,6 +18,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore">
<Version>7.0.14</Version>
</PackageReference>
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.7" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,24 @@
using MediatR;
namespace AutobusApi.Application.Buses.Commands.CreateBus;
public record CreateBusCommand : IRequest<int>
{
public int CompanyId { get; set; }
public string Number { get; set; } = null!;
public string Model { get; set; } = null!;
public int Capacity { get; set; }
public bool HasClimateControl { get; set; }
public bool HasWiFi { get; set; }
public bool HasMultimedia { get; set; }
public bool HasWC { get; set; }
public bool HasOutlets { get; set; }
}

View File

@ -0,0 +1,38 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Entities;
using MediatR;
namespace AutobusApi.Application.Buses.Commands.CreateBus;
public class CreateBusCommandHandler : IRequestHandler<CreateBusCommand, int>
{
private readonly IApplicationDbContext _dbContext;
public CreateBusCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> Handle(
CreateBusCommand request,
CancellationToken cancellationToken)
{
var bus = new Bus();
bus.CompanyId = request.CompanyId;
bus.Number = request.Number;
bus.Model = request.Model;
bus.Capacity = request.Capacity;
bus.HasClimateControl = request.HasClimateControl;
bus.HasWiFi = request.HasWiFi;
bus.HasMultimedia = request.HasMultimedia;
bus.HasWC = request.HasWC;
bus.HasOutlets = request.HasOutlets;
_dbContext.Vehicles.Add(bus);
await _dbContext.SaveChangesAsync(cancellationToken);
return bus.Id;
}
}

View File

@ -0,0 +1,15 @@
using FluentValidation;
namespace AutobusApi.Application.Buses.Commands.CreateBus;
public class CreateBusCommandValidator : AbstractValidator<CreateBusCommand>
{
public CreateBusCommandValidator()
{
RuleFor(v => v.Number).MinimumLength(8).MaximumLength(8);
RuleFor(v => v.Model).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.Capacity).GreaterThan(0);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Buses.Commands.DeleteBus;
public record DeleteBusCommand : IRequest
{
public int Id { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Buses.Commands.DeleteBus;
public class DeleteBusCommandHandler : IRequestHandler<DeleteBusCommand>
{
private readonly IApplicationDbContext _dbContext;
public DeleteBusCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
DeleteBusCommand request,
CancellationToken cancellationToken)
{
var bus = await _dbContext.Buses
.SingleOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (bus == null)
{
throw new NotFoundException();
}
_dbContext.Buses.Remove(bus);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Buses.Commands.DeleteBus;
public class DeleteBusCommandValidator : AbstractValidator<DeleteBusCommand>
{
public DeleteBusCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,26 @@
using MediatR;
namespace AutobusApi.Application.Buses.Commands.UpdateBus;
public record UpdateBusCommand : IRequest
{
public int Id { get; set; }
public int CompanyId { get; set; }
public string Number { get; set; } = null!;
public string Model { get; set; } = null!;
public int Capacity { get; set; }
public bool HasClimateControl { get; set; }
public bool HasWiFi { get; set; }
public bool HasMultimedia { get; set; }
public bool HasWC { get; set; }
public bool HasOutlets { get; set; }
}

View File

@ -0,0 +1,40 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
namespace AutobusApi.Application.Buses.Commands.UpdateBus;
public class UpdateBusCommandHandler : IRequestHandler<UpdateBusCommand>
{
private readonly IApplicationDbContext _dbContext;
public UpdateBusCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
UpdateBusCommand request,
CancellationToken cancellationToken)
{
var bus = await _dbContext.Buses
.FindAsync(new object[] { request.Id }, cancellationToken);
if (bus == null)
{
throw new NotFoundException();
}
bus.CompanyId = request.CompanyId;
bus.Number = request.Number;
bus.Model = request.Model;
bus.Capacity = request.Capacity;
bus.HasClimateControl = request.HasClimateControl;
bus.HasWiFi = request.HasWiFi;
bus.HasMultimedia = request.HasMultimedia;
bus.HasWC = request.HasWC;
bus.HasOutlets = request.HasOutlets;
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,19 @@
using FluentValidation;
namespace AutobusApi.Application.Buses.Commands.UpdateBus;
public class UpdateBusCommandValidator : AbstractValidator<UpdateBusCommand>
{
public UpdateBusCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
RuleFor(v => v.CompanyId).GreaterThan(0);
RuleFor(v => v.Number).MinimumLength(8).MaximumLength(8);
RuleFor(v => v.Model).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.Capacity).GreaterThan(0);
}
}

View File

@ -0,0 +1,27 @@
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Domain.Entities;
namespace AutobusApi.Application.Buses.Queries;
public class BusDto : IMapFrom<Bus>
{
public int Id { get; set; }
public int CompanyId { get; set; }
public string Number { get; set; } = null!;
public string Model { get; set; } = null!;
public int Capacity { get; set; }
public bool HasClimateControl { get; set; }
public bool HasWiFi { get; set; }
public bool HasMultimedia { get; set; }
public bool HasWC { get; set; }
public bool HasOutlets { get; set; }
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Buses.Queries.GetBus;
public record GetBusQuery : IRequest<BusDto>
{
public int Id { get; set; }
}

View File

@ -0,0 +1,38 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Buses.Queries.GetBus;
public class GetBusQueryHandler : IRequestHandler<GetBusQuery, BusDto>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetBusQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<BusDto> Handle(
GetBusQuery request,
CancellationToken cancellationToken)
{
var bus = await _dbContext.Buses
.ProjectTo<BusDto>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync(c => c.Id == request.Id);
if (bus == null)
{
throw new NotFoundException();
}
return bus;
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Buses.Queries.GetBus;
public class GetBusQueryValidator : AbstractValidator<GetBusQuery>
{
public GetBusQueryValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,13 @@
using AutobusApi.Application.Common.Models;
using MediatR;
namespace AutobusApi.Application.Buses.Queries.GetBusesWithPagination;
public record GetBusesWithPaginationQuery : IRequest<PaginatedList<BusDto>>
{
public string Sort { get; set; } = "";
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
namespace AutobusApi.Application.Buses.Queries.GetBusesWithPagination;
public class GetBusesWithPaginationQueryHandler : IRequestHandler<GetBusesWithPaginationQuery, PaginatedList<BusDto>>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetBusesWithPaginationQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<PaginatedList<BusDto>> Handle(
GetBusesWithPaginationQuery request,
CancellationToken cancellationToken)
{
return await _dbContext.Buses
.ProjectTo<BusDto>(_mapper.ConfigurationProvider)
.ApplySort(request.Sort)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Buses.Queries.GetBusesWithPagination;
public class GetBusesWithPaginationQueryValidator : AbstractValidator<GetBusesWithPaginationQuery>
{
public GetBusesWithPaginationQueryValidator()
{
RuleFor(v => v.PageNumber).GreaterThanOrEqualTo(1);
RuleFor(v => v.PageSize).GreaterThanOrEqualTo(1).LessThanOrEqualTo(50);
}
}

View File

@ -0,0 +1,10 @@
using MediatR;
namespace AutobusApi.Application.Cities.Commands.CreateCity;
public record CreateCityCommand : IRequest<int>
{
public string Name { get; set; } = null!;
public int RegionId { get; set; }
}

View File

@ -0,0 +1,31 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Entities;
using MediatR;
namespace AutobusApi.Application.Cities.Commands.CreateCity;
public class CreateCityCommandHandler : IRequestHandler<CreateCityCommand, int>
{
private readonly IApplicationDbContext _dbContext;
public CreateCityCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> Handle(
CreateCityCommand request,
CancellationToken cancellationToken)
{
var city = new City();
city.Name = request.Name;
city.RegionId = request.RegionId;
_dbContext.Cities.Add(city);
await _dbContext.SaveChangesAsync(cancellationToken);
return city.Id;
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Cities.Commands.CreateCity;
public class CreateCityCommandValidator : AbstractValidator<CreateCityCommand>
{
public CreateCityCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.RegionId).GreaterThan(0);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Cities.Commands.DeleteCity;
public record DeleteCityCommand : IRequest
{
public int Id { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Cities.Commands.DeleteCity;
public class DeleteCityCommandHandler : IRequestHandler<DeleteCityCommand>
{
private readonly IApplicationDbContext _dbContext;
public DeleteCityCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
DeleteCityCommand request,
CancellationToken cancellationToken)
{
var city = await _dbContext.Cities
.SingleOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (city == null)
{
throw new NotFoundException();
}
_dbContext.Cities.Remove(city);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Cities.Commands.DeleteCity;
public class DeleteCityCommandValidator : AbstractValidator<DeleteCityCommand>
{
public DeleteCityCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,12 @@
using MediatR;
namespace AutobusApi.Application.Cities.Commands.UpdateCity;
public record UpdateCityCommand : IRequest
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public int RegionId { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
namespace AutobusApi.Application.Cities.Commands.UpdateCity;
public class UpdateCityCommandHandler : IRequestHandler<UpdateCityCommand>
{
private readonly IApplicationDbContext _dbContext;
public UpdateCityCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
UpdateCityCommand request,
CancellationToken cancellationToken)
{
var city = await _dbContext.Cities
.FindAsync(new object[] { request.Id }, cancellationToken);
if (city == null)
{
throw new NotFoundException();
}
city.Name = request.Name;
city.RegionId = request.RegionId;
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,15 @@
using FluentValidation;
namespace AutobusApi.Application.Cities.Commands.UpdateCity;
public class UpdateCityCommandValidator : AbstractValidator<UpdateCityCommand>
{
public UpdateCityCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.Id).GreaterThan(0);
RuleFor(v => v.RegionId).GreaterThan(0);
}
}

View File

@ -0,0 +1,27 @@
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Domain.Entities;
using AutoMapper;
namespace AutobusApi.Application.Cities.Queries;
public class CityDto : IMapFrom<City>
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public int CountryId { get; set; }
public string CountryName { get; set; } = null!;
public int RegionId { get; set; }
public string RegionName { get; set; } = null!;
public void Mapping(Profile profile)
{
profile.CreateMap<City, CityDto>()
.ForMember(d => d.CountryId, opt => opt.MapFrom(s => s.Region.Country.Id))
.ForMember(d => d.CountryName, opt => opt.MapFrom(s => s.Region.Country.Name));
}
}

View File

@ -0,0 +1,13 @@
using AutobusApi.Application.Common.Models;
using MediatR;
namespace AutobusApi.Application.Cities.Queries.GetCitiesWithPagination;
public record GetCitiesWithPaginationQuery : IRequest<PaginatedList<CityDto>>
{
public string Sort { get; set; } = "";
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
namespace AutobusApi.Application.Cities.Queries.GetCitiesWithPagination;
public class GetCitiesWithPaginationQueryHandler : IRequestHandler<GetCitiesWithPaginationQuery, PaginatedList<CityDto>>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCitiesWithPaginationQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<PaginatedList<CityDto>> Handle(
GetCitiesWithPaginationQuery request,
CancellationToken cancellationToken)
{
return await _dbContext.Cities
.ProjectTo<CityDto>(_mapper.ConfigurationProvider)
.ApplySort(request.Sort)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Cities.Queries.GetCitiesWithPagination;
public class GetCitiesWithPaginationQueryValidator : AbstractValidator<GetCitiesWithPaginationQuery>
{
public GetCitiesWithPaginationQueryValidator()
{
RuleFor(v => v.PageNumber).GreaterThanOrEqualTo(1);
RuleFor(v => v.PageSize).GreaterThanOrEqualTo(1).LessThanOrEqualTo(50);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Cities.Queries.GetCity;
public record GetCityQuery : IRequest<CityDto>
{
public int Id { get; set; }
}

View File

@ -0,0 +1,36 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutoMapper;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Cities.Queries.GetCity;
public class GetCityQueryHandler : IRequestHandler<GetCityQuery, CityDto>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCityQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<CityDto> Handle(
GetCityQuery request,
CancellationToken cancellationToken)
{
var city = await _dbContext.Cities
.SingleOrDefaultAsync(c => c.Id == request.Id);
if (city == null)
{
throw new NotFoundException();
}
return _mapper.Map<CityDto>(city);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Cities.Queries.GetCity;
public class GetCityQueryValidator : AbstractValidator<GetCityQuery>
{
public GetCityQueryValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,3 @@
namespace AutobusApi.Application.Common.Exceptions;
public class NotFoundException : Exception { }

View File

@ -4,7 +4,7 @@ namespace AutobusApi.Application.Common.Interfaces;
public interface IIdentityService
{
Task RegisterAsync(string email, string password, CancellationToken cancellationToken);
Task<int> RegisterAsync(string email, string password, CancellationToken cancellationToken);
Task<TokensModel> LoginAsync(string email, string password, CancellationToken cancellationToken);

View File

@ -0,0 +1,156 @@
using System.Reflection;
using System.Linq.Dynamic.Core;
using System.Text;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using System.Dynamic;
namespace AutobusApi.Application.Common.Mappings;
public static class MappingExtensions
{
public static Task<PaginatedList<T>> PaginatedListAsync<T>(
this IQueryable<T> queryable,
int pageNumber,
int pageSize)
where T : class
{
return PaginatedList<T>.CreateAsync(queryable.AsNoTracking(), pageNumber, pageSize);
}
public static Task<List<T>> ProjectToListAsync<T>(
this IQueryable queryable,
IConfigurationProvider configuration)
where T : class
{
return queryable.ProjectTo<T>(configuration).AsNoTracking().ToListAsync();
}
public static IQueryable<T> ApplySort<T>(
this IQueryable<T> entities,
string? orderByQueryString)
{
if (!entities.Any() || String.IsNullOrWhiteSpace(orderByQueryString))
{
return entities;
}
var orderParams = orderByQueryString.Trim().Split(",");
var propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
var orderQueryBuilder = new StringBuilder();
foreach (var param in orderParams)
{
if (string.IsNullOrWhiteSpace(param))
{
continue;
}
var propertyFromQueryName = param[0] == '-' || param[0] == '+' ? param.Substring(1) : param;
var objectProperty = propertyInfos.FirstOrDefault(pi =>
pi.Name.Equals(propertyFromQueryName, StringComparison.InvariantCultureIgnoreCase));
if (objectProperty == null)
{
continue;
}
var sortingOrder = param[0] == '-' ? "descending" : "ascending";
orderQueryBuilder.Append($"{objectProperty.Name} {sortingOrder}, ");
}
var orderQuery = orderQueryBuilder.ToString().TrimEnd(',', ' ');
return entities.OrderBy(orderQuery);
}
public static IQueryable<ExpandoObject> ShapeData<T>(
this IQueryable<T> entities,
string? fieldsString)
{
var allProperties = GetAllProperties<T>();
var requiredProperties = GetRequiredProperties(fieldsString, allProperties);
return FetchData(entities, requiredProperties);
}
public static ExpandoObject ShapeData<T>(
this T entity,
string? fieldsString)
{
var allProperties = GetAllProperties<T>();
var requiredProperties = GetRequiredProperties(fieldsString, allProperties);
return FetchDataForEntity(entity, requiredProperties);
}
private static IEnumerable<PropertyInfo> GetAllProperties<T>()
{
return typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
}
private static IEnumerable<PropertyInfo> GetRequiredProperties(
string? fieldsString,
IEnumerable<PropertyInfo> properties)
{
var requiredProperties = new List<PropertyInfo>();
if (!string.IsNullOrWhiteSpace(fieldsString))
{
var fields = fieldsString.Split(',', StringSplitOptions.RemoveEmptyEntries);
foreach (var field in fields)
{
var property = properties.FirstOrDefault(pi => pi.Name.Equals(field.Trim(), StringComparison.InvariantCultureIgnoreCase));
if (property == null)
continue;
requiredProperties.Add(property);
}
}
else
{
requiredProperties = properties.ToList();
}
return requiredProperties;
}
private static IQueryable<ExpandoObject> FetchData<T>(
IQueryable<T> entities,
IEnumerable<PropertyInfo> requiredProperties)
{
var shapedData = new List<ExpandoObject>();
foreach (var entity in entities)
{
var shapedObject = FetchDataForEntity(entity, requiredProperties);
shapedData.Add(shapedObject);
}
return shapedData.AsQueryable();
}
private static ExpandoObject FetchDataForEntity<T>(
T entity,
IEnumerable<PropertyInfo> requiredProperties)
{
var shapedObject = new ExpandoObject();
foreach (var property in requiredProperties)
{
var objectPropertyValue = property.GetValue(entity);
shapedObject.TryAdd(property.Name, objectPropertyValue);
}
return shapedObject;
}
}

View File

@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Common.Models;
public class PaginatedList<T>
{
public IReadOnlyCollection<T> Items { get; }
public int PageNumber { get; }
public int TotalPages { get; }
public int TotalCount { get; }
public PaginatedList(IReadOnlyCollection<T> items, int count, int pageNumber, int pageSize)
{
PageNumber = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
TotalCount = count;
Items = items;
}
public bool HasPreviousPage => PageNumber > 1;
public bool HasNextPage => PageNumber < TotalPages;
public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
{
var count = await source.CountAsync();
var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
return new PaginatedList<T>(items, count, pageNumber, pageSize);
}
}

View File

@ -0,0 +1,32 @@
using MediatR;
namespace AutobusApi.Application.Companies.Commands.CreateCompany;
public record CreateCompanyCommand : IRequest<int>
{
public string Name { get; set; } = null!;
public string LegalAddress { get; set; } = null!;
public string ContactEmail { get; set; } = null!;
public string ContactPhoneNumber { get; set; } = null!;
public string OwnerEmail { get; set; } = null!;
public string OwnerPassword { get; set; } = null!;
public string OwnerFirstName { get; set; } = null!;
public string OwnerLastName { get; set; } = null!;
public string OwnerPatronymic { get; set; } = null!;
public string OwnerSex { get; set; } = null!;
public DateOnly OwnerBirthDate { get; set; }
public string OwnerDocumentType { get; set; } = null!;
public string OwnerDocumentInformation { get; set; } = null!;
}

View File

@ -0,0 +1,61 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Entities;
using AutobusApi.Domain.Enums;
using MediatR;
namespace AutobusApi.Application.Companies.Commands.CreateCompany;
public class CreateCompanyCommandHandler : IRequestHandler<CreateCompanyCommand, int>
{
private readonly IApplicationDbContext _dbContext;
private readonly IIdentityService _identityService;
public CreateCompanyCommandHandler(
IApplicationDbContext dbContext,
IIdentityService identityService)
{
_dbContext = dbContext;
_identityService = identityService;
}
public async Task<int> Handle(
CreateCompanyCommand request,
CancellationToken cancellationToken)
{
var company = new Company();
company.Name = request.Name;
company.LegalAddress = request.LegalAddress;
company.ContactPhoneNumber = request.ContactPhoneNumber;
company.ContactEmail = request.ContactEmail;
var userId = await _identityService.RegisterAsync(request.OwnerEmail, request.OwnerPassword, cancellationToken);
company.Employees = new List<Employee>()
{
new Employee()
{
IdentityId = userId,
FirstName = request.OwnerFirstName,
LastName = request.OwnerLastName,
Patronymic = request.OwnerPatronymic,
Sex = Enum.Parse<Sex>(request.OwnerSex),
BirthDate = request.OwnerBirthDate,
Documents = new List<EmployeeDocument>()
{
new EmployeeDocument()
{
Type = Enum.Parse<EmployeeDocumentType>(request.OwnerDocumentType),
Information = request.OwnerDocumentInformation
}
}
}
};
_dbContext.Companies.Add(company);
await _dbContext.SaveChangesAsync(cancellationToken);
return company.Id;
}
}

View File

@ -0,0 +1,47 @@
using AutobusApi.Domain.Enums;
using FluentValidation;
namespace AutobusApi.Application.Companies.Commands.CreateCompany;
public class CreateCompanyCommandValidator : AbstractValidator<CreateCompanyCommand>
{
public CreateCompanyCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.LegalAddress).MinimumLength(2).MaximumLength(256);
RuleFor(v => v.ContactPhoneNumber)
.NotEmpty().WithMessage("Phone number is required.")
.Matches(@"^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$").WithMessage("Phone number is invalid.");
RuleFor(v => v.ContactEmail)
.NotEmpty().WithMessage("Email address is required.")
.Matches(@"\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b").WithMessage("Email address is invalid.");
RuleFor(v => v.OwnerEmail)
.NotEmpty().WithMessage("Email address is required.")
.Matches(@"\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b").WithMessage("Email address is invalid.");
RuleFor(v => v.OwnerPassword)
.NotEmpty().WithMessage("Password is required.")
.MinimumLength(8).WithMessage("Password must be at least 8 characters long.")
.MaximumLength(64).WithMessage("Password must be at most 64 characters long.")
.Matches(@"(?=.*[A-Z]).*").WithMessage("Password must contain at least one uppercase letter.")
.Matches(@"(?=.*[a-z]).*").WithMessage("Password must contain at least one lowercase letter.")
.Matches(@"(?=.*[\d]).*").WithMessage("Password must contain at least one digit.")
.Matches(@"(?=.*[!@#$%^&*()]).*").WithMessage("Password must contain at least one of the following special charactters: !@#$%^&*().");
RuleFor(v => v.OwnerFirstName).MinimumLength(2).MaximumLength(32);
RuleFor(v => v.OwnerLastName).MinimumLength(2).MaximumLength(32);
RuleFor(v => v.OwnerPatronymic).MinimumLength(2).MaximumLength(32);
RuleFor(v => v.OwnerSex).Must(value => Enum.TryParse<Sex>(value, true, out _));
RuleFor(v => v.OwnerDocumentType).Must(value => Enum.TryParse<EmployeeDocumentType>(value, true, out _));
RuleFor(v => v.OwnerDocumentInformation).MinimumLength(2).MaximumLength(256);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Companies.Commands.DeleteCompany;
public record DeleteCompanyCommand : IRequest
{
public int Id { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Companies.Commands.DeleteCompany;
public class DeleteCompanyCommandHandler : IRequestHandler<DeleteCompanyCommand>
{
private readonly IApplicationDbContext _dbContext;
public DeleteCompanyCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
DeleteCompanyCommand request,
CancellationToken cancellationToken)
{
var company = await _dbContext.Companies
.SingleOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (company == null)
{
throw new NotFoundException();
}
_dbContext.Companies.Remove(company);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Companies.Commands.DeleteCompany;
public class DeleteCompanyCommandValidator : AbstractValidator<DeleteCompanyCommand>
{
public DeleteCompanyCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,16 @@
using MediatR;
namespace AutobusApi.Application.Companies.Commands.UpdateCompany;
public record UpdateCompanyCommand : IRequest
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public string LegalAddress { get; set; } = null!;
public string ContactEmail { get; set; } = null!;
public string ContactPhoneNumber { get; set; } = null!;
}

View File

@ -0,0 +1,35 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
namespace AutobusApi.Application.Companies.Commands.UpdateCompany;
public class UpdateCompanyCommandHandler : IRequestHandler<UpdateCompanyCommand>
{
private readonly IApplicationDbContext _dbContext;
public UpdateCompanyCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
UpdateCompanyCommand request,
CancellationToken cancellationToken)
{
var company = await _dbContext.Companies
.FindAsync(new object[] { request.Id }, cancellationToken);
if (company == null)
{
throw new NotFoundException();
}
company.Name = request.Name;
company.LegalAddress = request.LegalAddress;
company.ContactEmail = request.ContactEmail;
company.ContactPhoneNumber = request.ContactPhoneNumber;
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,23 @@
using FluentValidation;
namespace AutobusApi.Application.Companies.Commands.UpdateCompany;
public class UpdateCompanyCommandValidator : AbstractValidator<UpdateCompanyCommand>
{
public UpdateCompanyCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.LegalAddress).MinimumLength(2).MaximumLength(256);
RuleFor(v => v.ContactPhoneNumber)
.NotEmpty().WithMessage("Phone number is required.")
.Matches(@"^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$").WithMessage("Phone number is invalid.");
RuleFor(v => v.ContactEmail)
.NotEmpty().WithMessage("Email address is required.")
.Matches(@"\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b").WithMessage("Email address is invalid.");
}
}

View File

@ -0,0 +1,17 @@
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Domain.Entities;
namespace AutobusApi.Application.Companies.Queries;
public class CompanyDto : IMapFrom<Company>
{
public int Id { get; set; }
public string Name { get; set; } = null!;
public string LegalAddress { get; set; } = null!;
public string ContactEmail { get; set; } = null!;
public string ContactPhoneNumber { get; set; } = null!;
}

View File

@ -0,0 +1,13 @@
using AutobusApi.Application.Common.Models;
using MediatR;
namespace AutobusApi.Application.Companies.Queries.GetCompaniesWithPagination;
public record GetCompaniesWithPaginationQuery : IRequest<PaginatedList<CompanyDto>>
{
public string Sort { get; set; } = "";
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
namespace AutobusApi.Application.Companies.Queries.GetCompaniesWithPagination;
public class GetCompaniesWithPaginationQueryHandler : IRequestHandler<GetCompaniesWithPaginationQuery, PaginatedList<CompanyDto>>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCompaniesWithPaginationQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<PaginatedList<CompanyDto>> Handle(
GetCompaniesWithPaginationQuery request,
CancellationToken cancellationToken)
{
return await _dbContext.Companies
.ProjectTo<CompanyDto>(_mapper.ConfigurationProvider)
.ApplySort(request.Sort)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Companies.Queries.GetCompaniesWithPagination;
public class GetCompaniesWithPaginationQueryValidator : AbstractValidator<GetCompaniesWithPaginationQuery>
{
public GetCompaniesWithPaginationQueryValidator()
{
RuleFor(v => v.PageNumber).GreaterThanOrEqualTo(1);
RuleFor(v => v.PageSize).GreaterThanOrEqualTo(1).LessThanOrEqualTo(50);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Companies.Queries.GetCompany;
public record GetCompanyQuery : IRequest<CompanyDto>
{
public int Id { get; set; }
}

View File

@ -0,0 +1,38 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Companies.Queries.GetCompany;
public class GetCompanyQueryHandler : IRequestHandler<GetCompanyQuery, CompanyDto>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCompanyQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<CompanyDto> Handle(
GetCompanyQuery request,
CancellationToken cancellationToken)
{
var company = await _dbContext.Companies
.ProjectTo<CompanyDto>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync(c => c.Id == request.Id);
if (company == null)
{
throw new NotFoundException();
}
return company;
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Companies.Queries.GetCompany;
public class GetCompanyQueryValidator : AbstractValidator<GetCompanyQuery>
{
public GetCompanyQueryValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Countries.Commands.CreateCountry;
public record CreateCountryCommand : IRequest<int>
{
public string Name { get; set; } = null!;
}

View File

@ -0,0 +1,30 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Domain.Entities;
using MediatR;
namespace AutobusApi.Application.Countries.Commands.CreateCountry;
public class CreateCountryCommandHandler : IRequestHandler<CreateCountryCommand, int>
{
private readonly IApplicationDbContext _dbContext;
public CreateCountryCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<int> Handle(
CreateCountryCommand request,
CancellationToken cancellationToken)
{
var country = new Country();
country.Name = request.Name;
_dbContext.Countries.Add(country);
await _dbContext.SaveChangesAsync(cancellationToken);
return country.Id;
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Countries.Commands.CreateCountry;
public class CreateCountryCommandValidator : AbstractValidator<CreateCountryCommand>
{
public CreateCountryCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Countries.Commands.DeleteCountry;
public record DeleteCountryCommand : IRequest
{
public int Id { get; set; }
}

View File

@ -0,0 +1,33 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Countries.Commands.DeleteCountry;
public class DeleteCountryCommandHandler : IRequestHandler<DeleteCountryCommand>
{
private readonly IApplicationDbContext _dbContext;
public DeleteCountryCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
DeleteCountryCommand request,
CancellationToken cancellationToken)
{
var country = await _dbContext.Countries
.SingleOrDefaultAsync(c => c.Id == request.Id, cancellationToken);
if (country == null)
{
throw new NotFoundException();
}
_dbContext.Countries.Remove(country);
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Countries.Commands.DeleteCountry;
public class DeleteCountryCommandValidator : AbstractValidator<DeleteCountryCommand>
{
public DeleteCountryCommandValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,10 @@
using MediatR;
namespace AutobusApi.Application.Countries.Commands.UpdateCountry;
public record UpdateCountryCommand : IRequest
{
public int Id { get; set; }
public string Name { get; set; } = null!;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using MediatR;
namespace AutobusApi.Application.Countries.Commands.UpdateCountry;
public class UpdateCountryCommandHandler : IRequestHandler<UpdateCountryCommand>
{
private readonly IApplicationDbContext _dbContext;
public UpdateCountryCommandHandler(IApplicationDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Handle(
UpdateCountryCommand request,
CancellationToken cancellationToken)
{
var country = await _dbContext.Countries
.FindAsync(new object[] { request.Id }, cancellationToken);
if (country == null)
{
throw new NotFoundException();
}
country.Name = request.Name;
await _dbContext.SaveChangesAsync(cancellationToken);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Countries.Commands.UpdateCountry;
public class UpdateCountryCommandValidator : AbstractValidator<UpdateCountryCommand>
{
public UpdateCountryCommandValidator()
{
RuleFor(v => v.Name).MinimumLength(2).MaximumLength(64);
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,11 @@
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Domain.Entities;
namespace AutobusApi.Application.Countries.Queries;
public class CountryDto : IMapFrom<Country>
{
public int Id { get; set; }
public string Name { get; set; } = null!;
}

View File

@ -0,0 +1,13 @@
using AutobusApi.Application.Common.Models;
using MediatR;
namespace AutobusApi.Application.Countries.Queries.GetCountriesWithPagination;
public record GetCountriesWithPaginationQuery : IRequest<PaginatedList<CountryDto>>
{
public string Sort { get; set; } = "";
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}

View File

@ -0,0 +1,32 @@
using AutobusApi.Application.Common.Interfaces;
using AutobusApi.Application.Common.Mappings;
using AutobusApi.Application.Common.Models;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
namespace AutobusApi.Application.Countries.Queries.GetCountriesWithPagination;
public class GetCountriesWithPaginationQueryHandler : IRequestHandler<GetCountriesWithPaginationQuery, PaginatedList<CountryDto>>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCountriesWithPaginationQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<PaginatedList<CountryDto>> Handle(
GetCountriesWithPaginationQuery request,
CancellationToken cancellationToken)
{
return await _dbContext.Countries
.ProjectTo<CountryDto>(_mapper.ConfigurationProvider)
.ApplySort(request.Sort)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@ -0,0 +1,13 @@
using FluentValidation;
namespace AutobusApi.Application.Countries.Queries.GetCountriesWithPagination;
public class GetCountriesWithPaginationQueryValidator : AbstractValidator<GetCountriesWithPaginationQuery>
{
public GetCountriesWithPaginationQueryValidator()
{
RuleFor(v => v.PageNumber).GreaterThanOrEqualTo(1);
RuleFor(v => v.PageSize).GreaterThanOrEqualTo(1).LessThanOrEqualTo(50);
}
}

View File

@ -0,0 +1,8 @@
using MediatR;
namespace AutobusApi.Application.Countries.Queries.GetCountry;
public record GetCountryQuery : IRequest<CountryDto>
{
public int Id { get; set; }
}

View File

@ -0,0 +1,38 @@
using AutobusApi.Application.Common.Exceptions;
using AutobusApi.Application.Common.Interfaces;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using Microsoft.EntityFrameworkCore;
namespace AutobusApi.Application.Countries.Queries.GetCountry;
public class GetCountryQueryHandler : IRequestHandler<GetCountryQuery, CountryDto>
{
private readonly IApplicationDbContext _dbContext;
private readonly IMapper _mapper;
public GetCountryQueryHandler(
IApplicationDbContext dbContext,
IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<CountryDto> Handle(
GetCountryQuery request,
CancellationToken cancellationToken)
{
var country = await _dbContext.Countries
.ProjectTo<CountryDto>(_mapper.ConfigurationProvider)
.SingleOrDefaultAsync(c => c.Id == request.Id);
if (country == null)
{
throw new NotFoundException();
}
return country;
}
}

View File

@ -0,0 +1,11 @@
using FluentValidation;
namespace AutobusApi.Application.Countries.Queries.GetCountry;
public class GetCountryQueryValidator : AbstractValidator<GetCountryQuery>
{
public GetCountryQueryValidator()
{
RuleFor(v => v.Id).GreaterThan(0);
}
}

View File

@ -0,0 +1,31 @@
using MediatR;
namespace AutobusApi.Application.Employees.Commands.CreateEmployee;
public record CreateEmployeeCommand : IRequest<int>
{
public int CompanyId { get; set; }
public string Email { get; set; } = null!;
public string Password { get; set; } = null!;
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string Patronymic { get; set; } = null!;
public string Sex { get; set; } = null!;
public DateOnly BirthDate { get; set; }
public List<CreateEmployeeDocumentCommand> Documents { get; set; } = null!;
}
public record CreateEmployeeDocumentCommand
{
public string Type { get; set; } = null!;
public string Information { get; set; } = null!;
}

Some files were not shown because too many files have changed in this diff Show More