From 670166827ee9a8fb4decb762142458dd923aeb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leynier=20Guti=C3=A9rrez=20Gonz=C3=A1lez?= Date: Mon, 16 May 2022 00:48:46 -0400 Subject: [PATCH] feat: implement device entity and his repository and use case --- Gateways.Api/Controllers/DevicesController.cs | 16 ++++++++ .../Controllers/GatewaysController.cs | 8 ++-- Gateways.Api/MapperProfiles/DeviceProfile.cs | 16 ++++++++ Gateways.Api/MapperProfiles/GatewayProfile.cs | 1 + Gateways.Api/Models/DeviceModels.cs | 37 +++++++++++++++++++ Gateways.Api/Models/GatewayModels.cs | 12 ++++++ .../Bootstrapper.cs | 4 +- .../Entities/Device.cs | 18 +++++++++ .../Entities/Gateway.cs | 7 +++- .../Enums/DeviceStatus.cs | 7 ++++ .../UseCases/IDeviceUseCase.cs | 7 ++++ .../Repositories/IDeviceRepository.cs | 8 ++++ .../UseCases/DeviceUseCase.cs | 12 ++++++ .../UseCases/GatewayUseCase.cs | 1 + .../Controllers/CrudApiControllerBase.cs | 34 ++++++++++------- .../ObjectContext.cs | 13 +++++++ .../Repositories/DeviceRepository.cs | 13 +++++++ 17 files changed, 195 insertions(+), 19 deletions(-) create mode 100644 Gateways.Api/Controllers/DevicesController.cs create mode 100644 Gateways.Api/MapperProfiles/DeviceProfile.cs create mode 100644 Gateways.Api/Models/DeviceModels.cs create mode 100644 Gateways.Business.Contracts/Entities/Device.cs create mode 100644 Gateways.Business.Contracts/Enums/DeviceStatus.cs create mode 100644 Gateways.Business.Contracts/UseCases/IDeviceUseCase.cs create mode 100644 Gateways.Business.Implementations/Repositories/IDeviceRepository.cs create mode 100644 Gateways.Business.Implementations/UseCases/DeviceUseCase.cs create mode 100644 Gateways.Data.Implementations/Repositories/DeviceRepository.cs diff --git a/Gateways.Api/Controllers/DevicesController.cs b/Gateways.Api/Controllers/DevicesController.cs new file mode 100644 index 0000000..3b64783 --- /dev/null +++ b/Gateways.Api/Controllers/DevicesController.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using Gateways.Api.Models; +using Gateways.Business.Contracts.Entities; +using Gateways.Business.Contracts.UseCases; +using Gateways.Common.Controllers; +using Microsoft.EntityFrameworkCore; + +namespace Gateways.Api.Controllers; + +public class DevicesController : CrudApiControllerBase +{ + public DevicesController(IDeviceUseCase useCase, IMapper mapper) + : base(useCase, mapper, q => q.Include(d => d.Gateway)) + { + } +} diff --git a/Gateways.Api/Controllers/GatewaysController.cs b/Gateways.Api/Controllers/GatewaysController.cs index f43fea7..314096b 100644 --- a/Gateways.Api/Controllers/GatewaysController.cs +++ b/Gateways.Api/Controllers/GatewaysController.cs @@ -3,12 +3,14 @@ using Gateways.Business.Contracts.Entities; using Gateways.Business.Contracts.UseCases; using Gateways.Common.Controllers; +using Microsoft.EntityFrameworkCore; namespace Gateways.Api.Controllers; -public class GatewaysController : CrudApiControllerBase +public class GatewaysController : CrudApiControllerBase { - public GatewaysController(IGatewayUseCase useCase, IMapper mapper) : base(useCase, mapper) + public GatewaysController(IGatewayUseCase useCase, IMapper mapper) + : base(useCase, mapper, q => q.Include(g => g.Devices)) { } -} \ No newline at end of file +} diff --git a/Gateways.Api/MapperProfiles/DeviceProfile.cs b/Gateways.Api/MapperProfiles/DeviceProfile.cs new file mode 100644 index 0000000..e794620 --- /dev/null +++ b/Gateways.Api/MapperProfiles/DeviceProfile.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using Gateways.Api.Models; +using Gateways.Business.Contracts.Entities; + +namespace Gateways.Api.MapperProfiles; + +public class DeviceProfile : Profile +{ + public DeviceProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Gateways.Api/MapperProfiles/GatewayProfile.cs b/Gateways.Api/MapperProfiles/GatewayProfile.cs index d97a8a3..0c418c1 100644 --- a/Gateways.Api/MapperProfiles/GatewayProfile.cs +++ b/Gateways.Api/MapperProfiles/GatewayProfile.cs @@ -9,6 +9,7 @@ public class GatewayProfile : Profile public GatewayProfile() { CreateMap(); + CreateMap(); CreateMap(); CreateMap(); } diff --git a/Gateways.Api/Models/DeviceModels.cs b/Gateways.Api/Models/DeviceModels.cs new file mode 100644 index 0000000..c5ed3fc --- /dev/null +++ b/Gateways.Api/Models/DeviceModels.cs @@ -0,0 +1,37 @@ +using Gateways.Business.Contracts.Enums; +using System.ComponentModel.DataAnnotations; + +namespace Gateways.Api.Models; + +public class DeviceBaseModel +{ + [Required] + public string Vendor { get; set; } = default!; + [Required] + public DateTime DateCreated { get; set; } = DateTime.UtcNow; + [Required] + public DeviceStatus Status { get; set; } = DeviceStatus.Offline; + + [Required] + public string GatewayId { get; set; } = default!; +} + +public class DeviceGetModel : DeviceBaseModel +{ + public int Id { get; set; } = default!; +} + +public class DeviceGetDetailsModel : DeviceGetModel +{ + public GatewayGetModel Gateway { get; set; } = default!; +} + +public class DevicePostModel : DeviceBaseModel +{ + +} + +public class DevicePutModel : DeviceBaseModel +{ + +} diff --git a/Gateways.Api/Models/GatewayModels.cs b/Gateways.Api/Models/GatewayModels.cs index ec3c576..234fbf6 100644 --- a/Gateways.Api/Models/GatewayModels.cs +++ b/Gateways.Api/Models/GatewayModels.cs @@ -1,8 +1,15 @@ +using Gateways.Common.Validators; +using System.ComponentModel.DataAnnotations; + namespace Gateways.Api.Models; public class GatewayBaseModel { + [Required] public string Name { get; set; } = default!; + [Required] + [IPv4] + public string IPv4 { get; set; } = default!; } public class GatewayGetModel : GatewayBaseModel @@ -10,6 +17,11 @@ public class GatewayGetModel : GatewayBaseModel public string Id { get; set; } = default!; } +public class GatewayGetDetailsModel : GatewayGetModel +{ + public IEnumerable Devices { get; set; } = new List(); +} + public class GatewayPostModel : GatewayBaseModel { diff --git a/Gateways.Business.Bootstrapper/Bootstrapper.cs b/Gateways.Business.Bootstrapper/Bootstrapper.cs index c0b294c..60884a0 100644 --- a/Gateways.Business.Bootstrapper/Bootstrapper.cs +++ b/Gateways.Business.Bootstrapper/Bootstrapper.cs @@ -22,11 +22,13 @@ public static void Boot(this IServiceCollection services, IConfiguration configu }); services.AddScoped(); - + // UseCases + services.AddScoped(); services.AddScoped(); // Repositories + services.AddScoped(); services.AddScoped(); } } diff --git a/Gateways.Business.Contracts/Entities/Device.cs b/Gateways.Business.Contracts/Entities/Device.cs new file mode 100644 index 0000000..4b3f2b3 --- /dev/null +++ b/Gateways.Business.Contracts/Entities/Device.cs @@ -0,0 +1,18 @@ +using Gateways.Business.Contracts.Enums; +using System.ComponentModel.DataAnnotations; + +namespace Gateways.Business.Contracts.Entities; + +public class Device : Entity +{ + [Required] + public string Vendor { get; set; } = default!; + [Required] + public DateTime DateCreated { get; set; } = DateTime.UtcNow; + [Required] + public DeviceStatus Status { get; set; } = DeviceStatus.Offline; + + [Required] + public string GatewayId { get; set; } = default!; + public Gateway Gateway { get; set; } = default!; +} diff --git a/Gateways.Business.Contracts/Entities/Gateway.cs b/Gateways.Business.Contracts/Entities/Gateway.cs index 9d043a6..cf98a75 100644 --- a/Gateways.Business.Contracts/Entities/Gateway.cs +++ b/Gateways.Business.Contracts/Entities/Gateway.cs @@ -1,7 +1,12 @@ -namespace Gateways.Business.Contracts.Entities; +using System.ComponentModel.DataAnnotations; + +namespace Gateways.Business.Contracts.Entities; public class Gateway : Entity { + [Required] public string Name { get; set; } = default!; + [Required] public string IPv4 { get; set; } = default!; + public IEnumerable Devices { get; set; } = new List(); } diff --git a/Gateways.Business.Contracts/Enums/DeviceStatus.cs b/Gateways.Business.Contracts/Enums/DeviceStatus.cs new file mode 100644 index 0000000..f1d520c --- /dev/null +++ b/Gateways.Business.Contracts/Enums/DeviceStatus.cs @@ -0,0 +1,7 @@ +namespace Gateways.Business.Contracts.Enums; + +public enum DeviceStatus +{ + Offline, + Online, +} diff --git a/Gateways.Business.Contracts/UseCases/IDeviceUseCase.cs b/Gateways.Business.Contracts/UseCases/IDeviceUseCase.cs new file mode 100644 index 0000000..8af243e --- /dev/null +++ b/Gateways.Business.Contracts/UseCases/IDeviceUseCase.cs @@ -0,0 +1,7 @@ +using Gateways.Business.Contracts.Entities; + +namespace Gateways.Business.Contracts.UseCases; + +public interface IDeviceUseCase : IUseCase +{ +} diff --git a/Gateways.Business.Implementations/Repositories/IDeviceRepository.cs b/Gateways.Business.Implementations/Repositories/IDeviceRepository.cs new file mode 100644 index 0000000..2dbd782 --- /dev/null +++ b/Gateways.Business.Implementations/Repositories/IDeviceRepository.cs @@ -0,0 +1,8 @@ +using Gateways.Business.Contracts; +using Gateways.Business.Contracts.Entities; + +namespace Gateways.Business.Implementations.Repositories; + +public interface IDeviceRepository : IRepository +{ +} diff --git a/Gateways.Business.Implementations/UseCases/DeviceUseCase.cs b/Gateways.Business.Implementations/UseCases/DeviceUseCase.cs new file mode 100644 index 0000000..a8c2303 --- /dev/null +++ b/Gateways.Business.Implementations/UseCases/DeviceUseCase.cs @@ -0,0 +1,12 @@ +using Gateways.Business.Contracts.Entities; +using Gateways.Business.Contracts.UseCases; +using Gateways.Business.Implementations.Repositories; + +namespace Gateways.Business.Implementations.UseCases; + +public class DeviceUseCase : BaseUseCase, IDeviceUseCase +{ + public DeviceUseCase(IDeviceRepository repository) : base(repository) + { + } +} diff --git a/Gateways.Business.Implementations/UseCases/GatewayUseCase.cs b/Gateways.Business.Implementations/UseCases/GatewayUseCase.cs index 789fa8b..006323d 100644 --- a/Gateways.Business.Implementations/UseCases/GatewayUseCase.cs +++ b/Gateways.Business.Implementations/UseCases/GatewayUseCase.cs @@ -8,5 +8,6 @@ public class GatewayUseCase : BaseUseCase, IGatewayUseCase { public GatewayUseCase(IGatewayRepository repository) : base(repository) { + } } diff --git a/Gateways.Common/Controllers/CrudApiControllerBase.cs b/Gateways.Common/Controllers/CrudApiControllerBase.cs index 98c8ef6..4b62403 100644 --- a/Gateways.Common/Controllers/CrudApiControllerBase.cs +++ b/Gateways.Common/Controllers/CrudApiControllerBase.cs @@ -8,17 +8,22 @@ namespace Gateways.Common.Controllers; -public class CrudApiControllerBase : ApiControllerBase where TEntity : Entity +public class CrudApiControllerBase : ApiControllerBase where TEntity : Entity { - private readonly IUseCase useCase; + private readonly Func, IQueryable>? includer; + protected readonly IUseCase useCase; - public CrudApiControllerBase(IUseCase useCase, IMapper mapper) : base(mapper) + public CrudApiControllerBase( + IUseCase useCase, + IMapper mapper, + Func, IQueryable>? includer = null) : base(mapper) { + this.includer = includer; this.useCase = useCase; } [HttpGet] - public Response> GetAll() + public virtual Response> GetAll() { var models = useCase .AsNoTrackingWithIdentityResolution() @@ -27,18 +32,19 @@ public Response> GetAll() } [HttpGet("{id}")] - public Response Get(string id) + public virtual Response Get(TKey id) { - var model = useCase - .AsNoTrackingWithIdentityResolution() - .FirstOrDefault(g => g.Id == id); + IQueryable query = useCase.AsNoTrackingWithIdentityResolution(); + if (includer != null) + query = includer(query); + var model = query.FirstOrDefault(g => Equals(g.Id, id)); if (model == null) throw new NotFoundError(); - return OkResponse(model); + return OkResponse(model); } [HttpPost] - public Response Post([FromBody] TPost model) + public virtual Response Post([FromBody] TPost model) { var entity = mapper.Map(model); useCase.Add(entity); @@ -47,9 +53,9 @@ public Response Post([FromBody] TPost model) } [HttpPut("{id}")] - public Response Put(string id, [FromBody] TPut model) + public virtual Response Put(TKey id, [FromBody] TPut model) { - var entity = useCase.FirstOrDefault(g => g.Id == id); + var entity = useCase.FirstOrDefault(g => Equals(g.Id, id)); if (entity == null) throw new NotFoundError(); mapper.Map(model, entity); @@ -58,9 +64,9 @@ public Response Put(string id, [FromBody] TPut model) } [HttpDelete("{id}")] - public Response Delete(string id) + public virtual Response Delete(TKey id) { - var entity = useCase.FirstOrDefault(g => g.Id == id); + var entity = useCase.FirstOrDefault(g => Equals(g.Id, id)); if (entity == null) throw new NotFoundError(); useCase.Remove(entity); diff --git a/Gateways.Data.Implementations/ObjectContext.cs b/Gateways.Data.Implementations/ObjectContext.cs index f01d544..d3c3e34 100644 --- a/Gateways.Data.Implementations/ObjectContext.cs +++ b/Gateways.Data.Implementations/ObjectContext.cs @@ -6,8 +6,14 @@ namespace Gateways.Data.Implementations; public class ObjectContext : DbContext, IObjectContext { + #region Constructors + public ObjectContext(DbContextOptions options) : base(options) { } + #endregion + + #region Methods and Properties + IQueryable IObjectContext.Query() => Set(); void IObjectContext.Add(TEntity entity) => Set().Add(entity); @@ -20,5 +26,12 @@ public ObjectContext(DbContextOptions options) : base(options) { Task IObjectContext.CommitAsync() => SaveChangesAsync(); + #endregion + + #region DbSets + + public DbSet Devices { get; set; } = default!; public DbSet Gateways { get; set; } = default!; + + #endregion } diff --git a/Gateways.Data.Implementations/Repositories/DeviceRepository.cs b/Gateways.Data.Implementations/Repositories/DeviceRepository.cs new file mode 100644 index 0000000..59841c6 --- /dev/null +++ b/Gateways.Data.Implementations/Repositories/DeviceRepository.cs @@ -0,0 +1,13 @@ +using Gateways.Business.Contracts; +using Gateways.Business.Contracts.Entities; +using Gateways.Business.Implementations.Repositories; + +namespace Gateways.Data.Implementations.Repositories +{ + public class DeviceRepository : BaseRepository, IDeviceRepository + { + public DeviceRepository(IObjectContext context) : base(context) + { + } + } +}