From 49064c8f7d82772027533be2d0b60e975a286030 Mon Sep 17 00:00:00 2001 From: cuqmbr Date: Sat, 5 Nov 2022 20:26:07 +0200 Subject: [PATCH] chore: add CRUD api endpoints for city & address data objects --- Server/Configurations/MapperInitializer.cs | 6 + .../AddressManagementController.cs | 101 ++++++++++ .../Controllers/CityManagementController.cs | 101 ++++++++++ Server/Program.cs | 6 + Server/Services/AddressManagementService.cs | 185 ++++++++++++++++++ Server/Services/CityManagementService.cs | 185 ++++++++++++++++++ Server/Services/IAddressManagementService.cs | 17 ++ Server/Services/ICityManagementService.cs | 17 ++ Server/Services/StateManagementService.cs | 8 +- .../DataTransferObjects/AddressDto.cs | 16 +- SharedModels/DataTransferObjects/CityDto.cs | 21 +- SharedModels/DataTransferObjects/StateDto.cs | 7 +- .../AddressParameters.cs | 15 ++ .../QueryStringParameters/CityParameters.cs | 15 ++ SharedModels/Requests/RegistrationRequest.cs | 1 - 15 files changed, 691 insertions(+), 10 deletions(-) create mode 100644 Server/Controllers/AddressManagementController.cs create mode 100644 Server/Controllers/CityManagementController.cs create mode 100644 Server/Services/AddressManagementService.cs create mode 100644 Server/Services/CityManagementService.cs create mode 100644 Server/Services/IAddressManagementService.cs create mode 100644 Server/Services/ICityManagementService.cs create mode 100644 SharedModels/QueryStringParameters/AddressParameters.cs create mode 100644 SharedModels/QueryStringParameters/CityParameters.cs diff --git a/Server/Configurations/MapperInitializer.cs b/Server/Configurations/MapperInitializer.cs index a0a9e8d..3b44eaf 100644 --- a/Server/Configurations/MapperInitializer.cs +++ b/Server/Configurations/MapperInitializer.cs @@ -19,12 +19,18 @@ public class MapperInitializer : Profile CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); diff --git a/Server/Controllers/AddressManagementController.cs b/Server/Controllers/AddressManagementController.cs new file mode 100644 index 0000000..2f7ad85 --- /dev/null +++ b/Server/Controllers/AddressManagementController.cs @@ -0,0 +1,101 @@ +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Server.Services; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Controllers; + +[Route("api/addresses")] +[ApiController] +public class AddressManagementController : ControllerBase +{ + private readonly IAddressManagementService _addressManagementService; + + public AddressManagementController(IAddressManagementService addressManagementService) + { + _addressManagementService = addressManagementService; + } + + [HttpPost] + public async Task AddAddress(CreateAddressDto address) + { + var result = await _addressManagementService.AddAddress(address); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return CreatedAtAction(nameof(GetAddress), new {id = result.address.Id}, result.address); + } + + [HttpGet] + public async Task GetAddresses([FromQuery] AddressParameters parameters) + { + var result = await _addressManagementService.GetAddresses(parameters); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(result.pagingMetadata)); + + return Ok(result.addresses); + } + + [HttpGet("{id}")] + public async Task GetAddress(int id, [FromQuery] string? fields) + { + if (!await _addressManagementService.IsAddressExists(id)) + { + return NotFound(); + } + + var result = await _addressManagementService.GetAddress(id, fields); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return Ok(result.address); + } + + [HttpPut("{id}")] + public async Task UpdateRoute(int id, UpdateAddressDto address) + { + if (id != address.Id) + { + return BadRequest(); + } + + var result = await _addressManagementService.UpdateAddress(address); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return Ok(result.address); + } + + [HttpDelete("{id}")] + public async Task DeleteRoute(int id) + { + if (!await _addressManagementService.IsAddressExists(id)) + { + return NotFound(); + } + + var result = await _addressManagementService.DeleteAddress(id); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return NoContent(); + } +} \ No newline at end of file diff --git a/Server/Controllers/CityManagementController.cs b/Server/Controllers/CityManagementController.cs new file mode 100644 index 0000000..31c0f7f --- /dev/null +++ b/Server/Controllers/CityManagementController.cs @@ -0,0 +1,101 @@ +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Server.Services; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Controllers; + +[Route("api/cities")] +[ApiController] +public class CityManagementController : ControllerBase +{ + private readonly ICityManagementService _cityManagementService; + + public CityManagementController(ICityManagementService cityManagementService) + { + _cityManagementService = cityManagementService; + } + + [HttpPost] + public async Task AddCity(CreateCityDto city) + { + var result = await _cityManagementService.AddCity(city); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return CreatedAtAction(nameof(GetCity), new {id = result.city.Id}, result.city); + } + + [HttpGet] + public async Task GetCities([FromQuery] CityParameters parameters) + { + var result = await _cityManagementService.GetCities(parameters); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(result.pagingMetadata)); + + return Ok(result.cities); + } + + [HttpGet("{id}")] + public async Task GetCity(int id, [FromQuery] string? fields) + { + if (!await _cityManagementService.IsCityExists(id)) + { + return NotFound(); + } + + var result = await _cityManagementService.GetCity(id, fields); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return Ok(result.city); + } + + [HttpPut("{id}")] + public async Task UpdateRoute(int id, UpdateCityDto city) + { + if (id != city.Id) + { + return BadRequest(); + } + + var result = await _cityManagementService.UpdateCity(city); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return Ok(result.city); + } + + [HttpDelete("{id}")] + public async Task DeleteRoute(int id) + { + if (!await _cityManagementService.IsCityExists(id)) + { + return NotFound(); + } + + var result = await _cityManagementService.DeleteCity(id); + + if (!result.isSucceed) + { + return BadRequest(result.message); + } + + return NoContent(); + } +} \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index 9bfa1e9..023257e 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -88,14 +88,20 @@ builder.Services.AddAutoMapper(typeof(MapperInitializer)); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped, SortHelper>(); builder.Services.AddScoped, SortHelper>(); +builder.Services.AddScoped, SortHelper>(); +builder.Services.AddScoped, SortHelper
>(); builder.Services.AddScoped, DataShaper>(); builder.Services.AddScoped, DataShaper>(); +builder.Services.AddScoped, DataShaper>(); +builder.Services.AddScoped, DataShaper
>(); // Adding DB Context with PostgreSQL var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); diff --git a/Server/Services/AddressManagementService.cs b/Server/Services/AddressManagementService.cs new file mode 100644 index 0000000..9762b1d --- /dev/null +++ b/Server/Services/AddressManagementService.cs @@ -0,0 +1,185 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Server.Data; +using Server.Helpers; +using Server.Models; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Services; + +public class AddressManagementService : IAddressManagementService +{ + private readonly ApplicationDbContext _dbContext; + private readonly IMapper _mapper; + private readonly ISortHelper
_addressSortHelper; + private readonly IDataShaper
_addressDataShaper; + + public AddressManagementService(ApplicationDbContext dbContext, + IMapper mapper, ISortHelper
addressSortHelper, + IDataShaper
addressDataShaper) + { + _dbContext = dbContext; + _mapper = mapper; + _addressSortHelper = addressSortHelper; + _addressDataShaper = addressDataShaper; + } + + public async Task<(bool isSucceed, string message, AddressDto address)> AddAddress(CreateAddressDto createAddressDto) + { + var address = _mapper.Map
(createAddressDto); + + await _dbContext.Addresses.AddAsync(address); + await _dbContext.SaveChangesAsync(); + + return (true, String.Empty, _mapper.Map(address)); + } + + public async Task<(bool isSucceed, string message, IEnumerable addresses, + PagingMetadata
pagingMetadata)> GetAddresses(AddressParameters parameters) + { + var dbAddresses = _dbContext.Addresses.Include(a => a.City) + .ThenInclude(c => c.State).ThenInclude(s => s.Country) + .AsQueryable(); + + SearchByAllAddressFields(ref dbAddresses, parameters.Search); + SearchByAddressName(ref dbAddresses, parameters.Name); + SearchByCityId(ref dbAddresses, parameters.CityId); + + try + { + dbAddresses = _addressSortHelper.ApplySort(dbAddresses, parameters.Sort); + + // By calling Any() we will check if LINQ to Entities Query will be + // executed. If not it will throw an InvalidOperationException exception + var isExecuted = dbAddresses.Any(); + } + catch (Exception e) + { + return (false, "Invalid sorting string", null, null)!; + } + + var pagingMetadata = ApplyPaging(ref dbAddresses, parameters.PageNumber, + parameters.PageSize); + + var shapedAddressesData = _addressDataShaper.ShapeData(dbAddresses, parameters.Fields); + var addressDtos = shapedAddressesData.ToList().ConvertAll(a => _mapper.Map(a)); + + return (true, "", addressDtos, pagingMetadata); + + void SearchByAllAddressFields(ref IQueryable
addresses, + string? search) + { + if (!addresses.Any() || String.IsNullOrWhiteSpace(search)) + { + return; + } + + addresses = addresses.Where(a => + a.Name.ToLower().Contains(search.ToLower())); + } + + void SearchByCityId(ref IQueryable
addresses, + int? cityId) + { + if (!addresses.Any() || cityId == null) + { + return; + } + + addresses = addresses.Where(a => a.CityId == cityId); + } + + void SearchByAddressName(ref IQueryable
addresses, + string? addressName) + { + if (!addresses.Any() || String.IsNullOrWhiteSpace(addressName)) + { + return; + } + + addresses = addresses.Where(a => + a.Name.ToLower().Contains(addressName.Trim().ToLower())); + } + + PagingMetadata
ApplyPaging(ref IQueryable
addresses, + int pageNumber, int pageSize) + { + var metadata = new PagingMetadata
(addresses, + pageNumber, pageSize); + + addresses = addresses + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + return metadata; + } + } + + public async Task<(bool isSucceed, string message, AddressDto address)> GetAddress(int id, string? fields) + { + var dbAddress = await _dbContext.Addresses.Where(a => a.Id == id) + .Include(a => a.City).ThenInclude(c => c.State) + .ThenInclude(s => s.Country) + .FirstOrDefaultAsync(); + + if (dbAddress == null) + { + return (false, $"Address doesn't exist", null)!; + } + + if (String.IsNullOrWhiteSpace(fields)) + { + fields = AddressParameters.DefaultFields; + } + + var shapedAddressData = _addressDataShaper.ShapeData(dbAddress, fields); + var addressDto = _mapper.Map(shapedAddressData); + + return (true, "", addressDto); + } + + public async Task<(bool isSucceed, string message, UpdateAddressDto address)> UpdateAddress(UpdateAddressDto updateAddressDto) + { + var address = _mapper.Map
(updateAddressDto); + _dbContext.Entry(address).State = EntityState.Modified; + + try + { + await _dbContext.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!await IsAddressExists(updateAddressDto.Id)) + { + return (false, $"Address with id:{updateAddressDto.Id} doesn't exist", null)!; + } + + throw; + } + + var dbAddress = await _dbContext.Addresses.FirstOrDefaultAsync(a => a.Id == address.Id); + + return (true, String.Empty, _mapper.Map(dbAddress)); + } + + public async Task<(bool isSucceed, string message)> DeleteAddress(int id) + { + var dbAddress = await _dbContext.Addresses.FirstOrDefaultAsync(a => a.Id == id); + + if (dbAddress == null) + { + return (false, $"Address with id:{id} doesn't exist"); + } + + _dbContext.Addresses.Remove(dbAddress); + await _dbContext.SaveChangesAsync(); + + return (true, String.Empty); + } + + public async Task IsAddressExists(int id) + { + return await _dbContext.Addresses.AnyAsync(a => a.Id == id); + } +} \ No newline at end of file diff --git a/Server/Services/CityManagementService.cs b/Server/Services/CityManagementService.cs new file mode 100644 index 0000000..f32c86e --- /dev/null +++ b/Server/Services/CityManagementService.cs @@ -0,0 +1,185 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using Server.Data; +using Server.Helpers; +using Server.Models; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Services; + +public class CityManagementService : ICityManagementService +{ + private readonly ApplicationDbContext _dbContext; + private readonly IMapper _mapper; + private readonly ISortHelper _citySortHelper; + private readonly IDataShaper _cityDataShaper; + + public CityManagementService(ApplicationDbContext dbContext, + IMapper mapper, ISortHelper citySortHelper, + IDataShaper cityDataShaper) + { + _dbContext = dbContext; + _mapper = mapper; + _citySortHelper = citySortHelper; + _cityDataShaper = cityDataShaper; + } + + public async Task<(bool isSucceed, string message, CityDto city)> AddCity(CreateCityDto createCityDto) + { + var city = _mapper.Map(createCityDto); + + await _dbContext.Cities.AddAsync(city); + await _dbContext.SaveChangesAsync(); + + return (true, String.Empty, _mapper.Map(city)); + } + + public async Task<(bool isSucceed, string message, IEnumerable cities, + PagingMetadata pagingMetadata)> GetCities(CityParameters parameters) + { + var dbCities = _dbContext.Cities.Include(c => c.State) + .ThenInclude(s => s.Country).Include(c => c.Addresses) + .AsQueryable(); + + SearchByAllCityFields(ref dbCities, parameters.Search); + SearchByCityName(ref dbCities, parameters.Name); + SearchByStateId(ref dbCities, parameters.StateId); + + try + { + dbCities = _citySortHelper.ApplySort(dbCities, parameters.Sort); + + // By calling Any() we will check if LINQ to Entities Query will be + // executed. If not it will throw an InvalidOperationException exception + var isExecuted = dbCities.Any(); + } + catch (Exception e) + { + return (false, "Invalid sorting string", null, null)!; + } + + var pagingMetadata = ApplyPaging(ref dbCities, parameters.PageNumber, + parameters.PageSize); + + var shapedCitiesData = _cityDataShaper.ShapeData(dbCities, parameters.Fields); + var cityDtos = shapedCitiesData.ToList().ConvertAll(s => _mapper.Map(s)); + + return (true, "", cityDtos, pagingMetadata); + + void SearchByAllCityFields(ref IQueryable cities, + string? search) + { + if (!cities.Any() || String.IsNullOrWhiteSpace(search)) + { + return; + } + + cities = cities.Where(s => + s.Name.ToLower().Contains(search.ToLower())); + } + + void SearchByStateId(ref IQueryable cities, + int? stateId) + { + if (!cities.Any() || stateId == null) + { + return; + } + + cities = cities.Where(s => s.StateId == stateId); + } + + void SearchByCityName(ref IQueryable cities, + string? cityName) + { + if (!cities.Any() || String.IsNullOrWhiteSpace(cityName)) + { + return; + } + + cities = cities.Where(s => + s.Name.ToLower().Contains(cityName.Trim().ToLower())); + } + + PagingMetadata ApplyPaging(ref IQueryable cities, + int pageNumber, int pageSize) + { + var metadata = new PagingMetadata(cities, + pageNumber, pageSize); + + cities = cities + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize); + + return metadata; + } + } + + public async Task<(bool isSucceed, string message, CityDto city)> GetCity(int id, string? fields) + { + var dbCity = await _dbContext.Cities.Where(s => s.Id == id) + .Include(c => c.State).ThenInclude(s => s.Country) + .Include(c => c.Addresses) + .FirstOrDefaultAsync(); + + if (dbCity == null) + { + return (false, $"City doesn't exist", null)!; + } + + if (String.IsNullOrWhiteSpace(fields)) + { + fields = CityParameters.DefaultFields; + } + + var shapedCityData = _cityDataShaper.ShapeData(dbCity, fields); + var cityDto = _mapper.Map(shapedCityData); + + return (true, "", cityDto); + } + + public async Task<(bool isSucceed, string message, UpdateCityDto city)> UpdateCity(UpdateCityDto updateCityDto) + { + var city = _mapper.Map(updateCityDto); + _dbContext.Entry(city).State = EntityState.Modified; + + try + { + await _dbContext.SaveChangesAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!await IsCityExists(updateCityDto.Id)) + { + return (false, $"City with id:{updateCityDto.Id} doesn't exist", null)!; + } + + throw; + } + + var dbCity = await _dbContext.Cities.FirstOrDefaultAsync(s => s.Id == city.Id); + + return (true, String.Empty, _mapper.Map(dbCity)); + } + + public async Task<(bool isSucceed, string message)> DeleteCity(int id) + { + var dbCity = await _dbContext.Cities.FirstOrDefaultAsync(s => s.Id == id); + + if (dbCity == null) + { + return (false, $"City with id:{id} doesn't exist"); + } + + _dbContext.Cities.Remove(dbCity); + await _dbContext.SaveChangesAsync(); + + return (true, String.Empty); + } + + public async Task IsCityExists(int id) + { + return await _dbContext.Cities.AnyAsync(s => s.Id == id); + } +} \ No newline at end of file diff --git a/Server/Services/IAddressManagementService.cs b/Server/Services/IAddressManagementService.cs new file mode 100644 index 0000000..736d9a3 --- /dev/null +++ b/Server/Services/IAddressManagementService.cs @@ -0,0 +1,17 @@ +using Server.Models; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Services; + +public interface IAddressManagementService +{ + Task<(bool isSucceed, string message, AddressDto address)> AddAddress(CreateAddressDto createAddressDto); + + Task<(bool isSucceed, string message, IEnumerable addresses, + PagingMetadata
pagingMetadata)> GetAddresses(AddressParameters parameters); + Task<(bool isSucceed, string message, AddressDto address)> GetAddress(int id, string? fields); + Task<(bool isSucceed, string message, UpdateAddressDto address)> UpdateAddress(UpdateAddressDto updateAddressDto); + Task<(bool isSucceed, string message)> DeleteAddress(int id); + Task IsAddressExists(int id); +} \ No newline at end of file diff --git a/Server/Services/ICityManagementService.cs b/Server/Services/ICityManagementService.cs new file mode 100644 index 0000000..bda8445 --- /dev/null +++ b/Server/Services/ICityManagementService.cs @@ -0,0 +1,17 @@ +using Server.Models; +using SharedModels.DataTransferObjects; +using SharedModels.QueryStringParameters; + +namespace Server.Services; + +public interface ICityManagementService +{ + Task<(bool isSucceed, string message, CityDto city)> AddCity(CreateCityDto createCityDto); + + Task<(bool isSucceed, string message, IEnumerable cities, + PagingMetadata pagingMetadata)> GetCities(CityParameters parameters); + Task<(bool isSucceed, string message, CityDto city)> GetCity(int id, string? fields); + Task<(bool isSucceed, string message, UpdateCityDto city)> UpdateCity(UpdateCityDto updateCityDto); + Task<(bool isSucceed, string message)> DeleteCity(int id); + Task IsCityExists(int id); +} \ No newline at end of file diff --git a/Server/Services/StateManagementService.cs b/Server/Services/StateManagementService.cs index 243466c..68c954f 100644 --- a/Server/Services/StateManagementService.cs +++ b/Server/Services/StateManagementService.cs @@ -45,7 +45,7 @@ public class StateManagementService : IStateManagementService SearchByAllStateFields(ref dbStates, parameters.Search); SearchByStateName(ref dbStates, parameters.Name); - SearchByStateCountryId(ref dbStates, parameters.CountryId); + SearchByCountryId(ref dbStates, parameters.CountryId); try { @@ -80,7 +80,7 @@ public class StateManagementService : IStateManagementService s.Name.ToLower().Contains(search.ToLower())); } - void SearchByStateCountryId(ref IQueryable states, + void SearchByCountryId(ref IQueryable states, int? countryId) { if (!states.Any() || countryId == null) @@ -88,9 +88,7 @@ public class StateManagementService : IStateManagementService return; } - states = states.Where(s => - s.CountryId.ToString().ToLower() - .Contains(countryId.ToString()!.Trim().ToLower())); + states = states.Where(s => s.CountryId == countryId); } void SearchByStateName(ref IQueryable states, diff --git a/SharedModels/DataTransferObjects/AddressDto.cs b/SharedModels/DataTransferObjects/AddressDto.cs index fa5945b..b328d02 100644 --- a/SharedModels/DataTransferObjects/AddressDto.cs +++ b/SharedModels/DataTransferObjects/AddressDto.cs @@ -6,7 +6,7 @@ public class AddressDto : CreateAddressDto { public int Id { get; set; } - public CityDto City { get; set; } = null!; + public InAddressCityDto City { get; set; } = null!; public virtual IList RouteAddresses { get; set; } = null!; } @@ -27,4 +27,18 @@ public class CreateAddressDto [Required] public int CityId { get; set; } +} + +public class UpdateAddressDto : CreateAddressDto +{ + [Required] + public int Id { get; set; } +} + +public class InCityAddressDto +{ + public int Id { get; set; } + public string Name { get; set; } = null!; + public double Latitude { get; set; } + public double Longitude { get; set; } } \ No newline at end of file diff --git a/SharedModels/DataTransferObjects/CityDto.cs b/SharedModels/DataTransferObjects/CityDto.cs index 04c8582..824a272 100644 --- a/SharedModels/DataTransferObjects/CityDto.cs +++ b/SharedModels/DataTransferObjects/CityDto.cs @@ -6,9 +6,9 @@ public class CityDto : CreateCityDto { public int Id { get; set; } - public StateDto State { get; set; } = null!; + public InCityStateDto State { get; set; } = null!; - public virtual IList? Addresses { get; set; } + public virtual IList? Addresses { get; set; } } public class CreateCityDto @@ -19,4 +19,21 @@ public class CreateCityDto [Required] public int StateId { get; set; } +} + +public class UpdateCityDto : CreateCityDto +{ + [Required] + public int Id { get; set; } +} + +public class InStateCityDto +{ + public int Id { get; set; } + public string Name { get; set; } = null!; +} + +public class InAddressCityDto +{ + public string Name { get; set; } = null!; } \ No newline at end of file diff --git a/SharedModels/DataTransferObjects/StateDto.cs b/SharedModels/DataTransferObjects/StateDto.cs index 16254ec..49f2e56 100644 --- a/SharedModels/DataTransferObjects/StateDto.cs +++ b/SharedModels/DataTransferObjects/StateDto.cs @@ -7,7 +7,7 @@ public class StateDto : CreateStateDto public int Id { get; set; } public InStateCountryDto Country { get; set; } = null!; - public virtual IList Cities { get; set; } = null!; + public virtual IList Cities { get; set; } = null!; } public class CreateStateDto @@ -30,4 +30,9 @@ public class InCountryStateDto { public int Id { get; set; } public string Name { get; set; } = null!; +} + +public class InCityStateDto +{ + public string Name { get; set; } = null!; } \ No newline at end of file diff --git a/SharedModels/QueryStringParameters/AddressParameters.cs b/SharedModels/QueryStringParameters/AddressParameters.cs new file mode 100644 index 0000000..9eba78c --- /dev/null +++ b/SharedModels/QueryStringParameters/AddressParameters.cs @@ -0,0 +1,15 @@ +namespace SharedModels.QueryStringParameters; + +public class AddressParameters : QueryStringParameters +{ + public const string DefaultFields = "id,name,cityId"; + + public AddressParameters() + { + Sort = "id"; + Fields = DefaultFields; + } + + public string? Name { get; set; } + public int? CityId { get; set; } +} \ No newline at end of file diff --git a/SharedModels/QueryStringParameters/CityParameters.cs b/SharedModels/QueryStringParameters/CityParameters.cs new file mode 100644 index 0000000..9141345 --- /dev/null +++ b/SharedModels/QueryStringParameters/CityParameters.cs @@ -0,0 +1,15 @@ +namespace SharedModels.QueryStringParameters; + +public class CityParameters : QueryStringParameters +{ + public const string DefaultFields = "id,name,stateId"; + + public CityParameters() + { + Sort = "id"; + Fields = DefaultFields; + } + + public string? Name { get; set; } + public int? StateId { get; set; } +} \ No newline at end of file diff --git a/SharedModels/Requests/RegistrationRequest.cs b/SharedModels/Requests/RegistrationRequest.cs index 0d5083e..9f964e5 100644 --- a/SharedModels/Requests/RegistrationRequest.cs +++ b/SharedModels/Requests/RegistrationRequest.cs @@ -4,7 +4,6 @@ namespace SharedModels.Requests; public class RegistrationRequest { - [Required] public string Username { get; set; } = null!; [Required] public string Email { get; set; } = null!;