From ba0531d8858560e17952e204d91e50558f39b9cd Mon Sep 17 00:00:00 2001 From: Simon Geering <25039878+SimonGeering@users.noreply.github.com> Date: Tue, 1 Sep 2020 15:22:41 +0100 Subject: [PATCH] #131 Added Contact controller REST API --- .../AdminAssistant.Blazor.Server.csproj | 1 - .../ContactController.ContactResponseDto.cs | 12 ++++ .../v1/ContactsModule/ContactController.cs | 36 ++++++++++ ...utoMapper_WebAPIMappingProfile_UnitTest.cs | 17 +++++ .../ContactController_UnitTest.cs | 67 +++++++++++++++++++ src/AdminAssistant/AdminAssistant.csproj | 1 - src/AdminAssistant/DomainModel/Factory.cs | 4 ++ .../ContactsModule/Builders/ContactBuilder.cs | 37 ++++++++++ .../ContactsModule/CQRS/ContactQuery.cs | 10 +++ .../Modules/ContactsModule/Contact.cs | 16 +++++ 10 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.ContactResponseDto.cs create mode 100644 src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.cs create mode 100644 src/AdminAssistant.Test/WebAPI/v1/ContactsModule/ContactController_UnitTest.cs create mode 100644 src/AdminAssistant/DomainModel/Modules/ContactsModule/Builders/ContactBuilder.cs create mode 100644 src/AdminAssistant/DomainModel/Modules/ContactsModule/CQRS/ContactQuery.cs create mode 100644 src/AdminAssistant/DomainModel/Modules/ContactsModule/Contact.cs diff --git a/src/AdminAssistant.Blazor/Server/AdminAssistant.Blazor.Server.csproj b/src/AdminAssistant.Blazor/Server/AdminAssistant.Blazor.Server.csproj index fbfef81a..b23d6d0c 100644 --- a/src/AdminAssistant.Blazor/Server/AdminAssistant.Blazor.Server.csproj +++ b/src/AdminAssistant.Blazor/Server/AdminAssistant.Blazor.Server.csproj @@ -58,7 +58,6 @@ - diff --git a/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.ContactResponseDto.cs b/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.ContactResponseDto.cs new file mode 100644 index 00000000..6865d9bb --- /dev/null +++ b/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.ContactResponseDto.cs @@ -0,0 +1,12 @@ +using AdminAssistant.DomainModel.Modules.ContactsModule; +using AdminAssistant.Framework.TypeMapping; + +namespace AdminAssistant.WebAPI.v1.ContactsModule +{ + public class ContactResponseDto : IMapFrom + { + public int ContactID { get; set; } + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + } +} diff --git a/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.cs b/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.cs new file mode 100644 index 00000000..6c9a55c6 --- /dev/null +++ b/src/AdminAssistant.Blazor/Server/WebAPI/v1/ContactsModule/ContactController.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using AdminAssistant.DomainModel.Modules.ContactsModule.CQRS; +using AdminAssistant.Infra.Providers; +using AutoMapper; +using MediatR; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Swashbuckle.AspNetCore.Annotations; + +namespace AdminAssistant.WebAPI.v1.ContactsModule +{ + [ApiController] + [Route("api/v1/core/[controller]")] + [ApiExplorerSettings(GroupName = "Contacts - Contact")] + public class ContactController : WebAPIControllerBase + { + public ContactController(IMapper mapper, IMediator mediator, ILoggingProvider loggingProvider) + : base(mapper, mediator, loggingProvider) + { + } + + [HttpGet] + [SwaggerOperation("Lists all contacts", OperationId = "GetContact")] + [SwaggerResponse(StatusCodes.Status200OK, "Ok - returns a list of ContactResponseDto", type: typeof(IEnumerable))] + public async Task>> GetContacts() + { + Log.Start(); + + var result = await Mediator.Send(new ContactQuery()).ConfigureAwait(false); + var response = Mapper.Map>(result.Value); + + return Log.Finish(Ok(response)); + } + } +} diff --git a/src/AdminAssistant.Test/AutoMapper_WebAPIMappingProfile_UnitTest.cs b/src/AdminAssistant.Test/AutoMapper_WebAPIMappingProfile_UnitTest.cs index e0fac065..fa2b2056 100644 --- a/src/AdminAssistant.Test/AutoMapper_WebAPIMappingProfile_UnitTest.cs +++ b/src/AdminAssistant.Test/AutoMapper_WebAPIMappingProfile_UnitTest.cs @@ -5,6 +5,7 @@ using AdminAssistant.DomainModel.Modules.AssetRegisterModule; using AdminAssistant.DomainModel.Modules.BudgetModule; using AdminAssistant.DomainModel.Modules.CalendarModule; +using AdminAssistant.DomainModel.Modules.ContactsModule; using AdminAssistant.DomainModel.Modules.CoreModule; using AdminAssistant.DomainModel.Modules.DocumentsModule; using AdminAssistant.DomainModel.Modules.TasksModule; @@ -12,6 +13,7 @@ using AdminAssistant.WebAPI.v1.AssetRegisterModule; using AdminAssistant.WebAPI.v1.BudgetModule; using AdminAssistant.WebAPI.v1.CalendarModule; +using AdminAssistant.WebAPI.v1.ContactsModule; using AdminAssistant.WebAPI.v1.CoreModule; using AdminAssistant.WebAPI.v1.DocumentsModule; using AdminAssistant.WebAPI.v1.TasksModule; @@ -109,6 +111,21 @@ public void ShouldSupportCalendarModuleMappingFromSourceToDestination(Type sourc result.Should().NotBeNull(); } + [Theory] + [Trait("Category", "Unit")] + [InlineData(typeof(Contact), typeof(ContactResponseDto))] + public void ShouldSupportContactsModuleMappingFromSourceToDestination(Type source, Type destination) + { + // Arrange + var instance = Activator.CreateInstance(source); + + // Act + var result = _mapper.Map(instance, source, destination); + + // Assert + result.Should().NotBeNull(); + } + [Theory] [Trait("Category", "Unit")] [InlineData(typeof(Currency), typeof(CurrencyResponseDto))] diff --git a/src/AdminAssistant.Test/WebAPI/v1/ContactsModule/ContactController_UnitTest.cs b/src/AdminAssistant.Test/WebAPI/v1/ContactsModule/ContactController_UnitTest.cs new file mode 100644 index 00000000..ab50d2cc --- /dev/null +++ b/src/AdminAssistant.Test/WebAPI/v1/ContactsModule/ContactController_UnitTest.cs @@ -0,0 +1,67 @@ +#pragma warning disable CA1707 // Identifiers should not contain underscores +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AdminAssistant.DomainModel; +using AdminAssistant.DomainModel.Modules.ContactsModule; +using AdminAssistant.DomainModel.Modules.ContactsModule.CQRS; +using Ardalis.Result; +using AutoMapper; +using FluentAssertions; +using MediatR; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Moq; +using Xunit; + +namespace AdminAssistant.WebAPI.v1.ContactsModule +{ + public class ContactController_GetContacts + { + [Fact] + [Trait("Category", "Unit")] + public async Task Returns_Status200OK_With_AListOfContacts_Given_NoArguments() + { + // Arrange + var documents = new List() + { + Factory.Contact.WithTestData(10).Build(), + Factory.Contact.WithTestData(20).Build() + }; + + var services = new ServiceCollection(); + services.AddMockServerSideLogging(); + services.AddAutoMapper(typeof(MappingProfile)); + + var mockMediator = new Mock(); + mockMediator.Setup(x => x.Send(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(Result>.Success(documents))); + + services.AddTransient((sp) => mockMediator.Object); + services.AddTransient(); + + // Act + var response = await services.BuildServiceProvider().GetRequiredService().GetContacts().ConfigureAwait(false); + + // Assert + response.Result.Should().BeOfType(); + response.Value.Should().BeNull(); + + var result = (OkObjectResult)response.Result; + result.Value.Should().BeAssignableTo>(); + + //var value = ((IEnumerable)result.Value).ToArray(); + //value.Should().HaveCount(currencies.Count); + + //var expected = currencies.ToArray(); + //for (int i = 0; i < expected.Length; i++) + //{ + // value[i].CurrencyID.Should().Be(expected[i].CurrencyID); + // value[i].Symbol.Should().Be(expected[i].Symbol); + // value[i].DecimalFormat.Should().Be(expected[i].DecimalFormat); + //} + } + } +} +#pragma warning restore CA1707 // Identifiers should not contain underscores diff --git a/src/AdminAssistant/AdminAssistant.csproj b/src/AdminAssistant/AdminAssistant.csproj index 265c6179..c4fa1601 100644 --- a/src/AdminAssistant/AdminAssistant.csproj +++ b/src/AdminAssistant/AdminAssistant.csproj @@ -62,7 +62,6 @@ - diff --git a/src/AdminAssistant/DomainModel/Factory.cs b/src/AdminAssistant/DomainModel/Factory.cs index 3eeb36c5..5515dcb3 100644 --- a/src/AdminAssistant/DomainModel/Factory.cs +++ b/src/AdminAssistant/DomainModel/Factory.cs @@ -2,6 +2,7 @@ using AdminAssistant.DomainModel.Modules.AssetRegisterModule.Builders; using AdminAssistant.DomainModel.Modules.BudgetModule.Builders; using AdminAssistant.DomainModel.Modules.CalendarModule.Builders; +using AdminAssistant.DomainModel.Modules.ContactsModule.Builders; using AdminAssistant.DomainModel.Modules.CoreModule.Builders; using AdminAssistant.DomainModel.Modules.DocumentsModule.Builders; using AdminAssistant.DomainModel.Modules.TasksModule.Builders; @@ -26,6 +27,9 @@ public static class Factory // Calendar Module ... public static IReminderBuilder Reminder => new ReminderBuilder(); + // Contact Module ... + public static IContactBuilder Contact => new ContactBuilder(); + // Core Module ... public static ICurrencyBuilder Currency => new CurrencyBuilder(); diff --git a/src/AdminAssistant/DomainModel/Modules/ContactsModule/Builders/ContactBuilder.cs b/src/AdminAssistant/DomainModel/Modules/ContactsModule/Builders/ContactBuilder.cs new file mode 100644 index 00000000..66066f0c --- /dev/null +++ b/src/AdminAssistant/DomainModel/Modules/ContactsModule/Builders/ContactBuilder.cs @@ -0,0 +1,37 @@ +namespace AdminAssistant.DomainModel.Modules.ContactsModule.Builders +{ + public interface IContactBuilder + { + Contact Build(); + IContactBuilder WithTestData(int assetID = Constants.UnknownRecordID); + IContactBuilder WithFirstName(string firstName); + IContactBuilder WithLastName(string lastName); + } + internal class ContactBuilder : Contact, IContactBuilder + { + public static Contact Default(IContactBuilder builder) => builder.Build(); + public static Contact Default(ContactBuilder builder) => builder.Build(); + + public Contact Build() => this; + + public IContactBuilder WithTestData(int assetID = Constants.UnknownRecordID) + { + ContactID = assetID; + FirstName = "Fred"; + LastName = "Blogs"; + return this; + } + + public IContactBuilder WithFirstName(string firstName) + { + FirstName = firstName; + return this; + } + + public IContactBuilder WithLastName(string lastName) + { + LastName = lastName; + return this; + } + } +} diff --git a/src/AdminAssistant/DomainModel/Modules/ContactsModule/CQRS/ContactQuery.cs b/src/AdminAssistant/DomainModel/Modules/ContactsModule/CQRS/ContactQuery.cs new file mode 100644 index 00000000..984417be --- /dev/null +++ b/src/AdminAssistant/DomainModel/Modules/ContactsModule/CQRS/ContactQuery.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Ardalis.Result; +using MediatR; + +namespace AdminAssistant.DomainModel.Modules.ContactsModule.CQRS +{ + public class ContactQuery : IRequest>> + { + } +} diff --git a/src/AdminAssistant/DomainModel/Modules/ContactsModule/Contact.cs b/src/AdminAssistant/DomainModel/Modules/ContactsModule/Contact.cs new file mode 100644 index 00000000..959347de --- /dev/null +++ b/src/AdminAssistant/DomainModel/Modules/ContactsModule/Contact.cs @@ -0,0 +1,16 @@ +using AdminAssistant.Infra.DAL; + +namespace AdminAssistant.DomainModel.Modules.ContactsModule +{ + public class Contact : IDatabasePersistable + { + public const int ContactFirstNameMaxLength = Constants.NameMaxLength; + public const int ContactLastNameMaxLength = Constants.NameMaxLength; + + public int ContactID { get; set; } + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + + public int PrimaryKey => ContactID; + } +}