diff --git a/TickAPI/TickAPI.Tests/Events/Controllers/EventsControllerTests.cs b/TickAPI/TickAPI.Tests/Events/Controllers/EventsControllerTests.cs index 041241f..60e6cc7 100644 --- a/TickAPI/TickAPI.Tests/Events/Controllers/EventsControllerTests.cs +++ b/TickAPI/TickAPI.Tests/Events/Controllers/EventsControllerTests.cs @@ -20,6 +20,8 @@ namespace TickAPI.Tests.Events.Controllers; public class EventsControllerTests { + private readonly EventFiltersDto _emptyFilters = new EventFiltersDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null); + [Fact] public async Task CreateEvent_WhenDataIsValid_ShouldReturnSuccess() { @@ -178,14 +180,14 @@ public async Task GetOrganizerEvents_WhenAllOperationsSucceed_ShouldReturnOkWith var eventServiceMock = new Mock(); eventServiceMock - .Setup(m => m.GetOrganizerEventsAsync(organizer, page, pageSize)) + .Setup(m => m.GetOrganizerEventsAsync(organizer, page, pageSize, _emptyFilters)) .ReturnsAsync(Result>.Success(paginatedData)); var sut = new EventsController(eventServiceMock.Object, claimsServiceMock.Object, organizerServiceMock.Object); sut.ControllerContext = controllerContext; // Act - var response = await sut.GetOrganizerEvents(pageSize, page); + var response = await sut.GetOrganizerEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); @@ -228,7 +230,7 @@ public async Task GetOrganizerEvents_WhenEmailClaimIsMissing_ShouldReturnBadRequ }; // Act - var response = await sut.GetOrganizerEvents(pageSize, page); + var response = await sut.GetOrganizerEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); @@ -275,7 +277,7 @@ public async Task GetOrganizerEvents_WhenOrganizerIsNotFound_ShouldReturnNotFoun sut.ControllerContext = controllerContext; // Act - var response = await sut.GetOrganizerEvents(pageSize, page); + var response = await sut.GetOrganizerEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); @@ -320,14 +322,14 @@ public async Task GetOrganizerEvents_WhenPaginationFails_ShouldReturnBadRequest( var eventServiceMock = new Mock(); eventServiceMock - .Setup(m => m.GetOrganizerEventsAsync(organizer, page, pageSize)) + .Setup(m => m.GetOrganizerEventsAsync(organizer, page, pageSize, _emptyFilters)) .ReturnsAsync(Result>.Failure(StatusCodes.Status400BadRequest, errorMessage)); var sut = new EventsController(eventServiceMock.Object, claimsServiceMock.Object, organizerServiceMock.Object); sut.ControllerContext = controllerContext; // Act - var response = await sut.GetOrganizerEvents(pageSize, page); + var response = await sut.GetOrganizerEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); @@ -467,13 +469,13 @@ public async Task GetEvents_WhenAllOperationsSucceed_ShouldReturnOkWithPaginated ); eventServiceMock - .Setup(m => m.GetEventsAsync(page, pageSize)) + .Setup(m => m.GetEventsAsync(page, pageSize, _emptyFilters)) .ReturnsAsync(Result>.Success(paginatedData)); var sut = new EventsController(eventServiceMock.Object, claimsServiceMock.Object, organizerServiceMock.Object); // Act - var response = await sut.GetEvents(pageSize, page); + var response = await sut.GetEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); @@ -504,13 +506,13 @@ public async Task GetEvents_WhenOperationFails_ShouldReturnErrorWithCorrectStatu var organizerServiceMock = new Mock(); eventServiceMock - .Setup(m => m.GetEventsAsync(page, pageSize)) + .Setup(m => m.GetEventsAsync(page, pageSize, _emptyFilters)) .ReturnsAsync(Result>.Failure(statusCode, errorMessage)); var sut = new EventsController(eventServiceMock.Object, claimsServiceMock.Object, organizerServiceMock.Object); // Act - var response = await sut.GetEvents(pageSize, page); + var response = await sut.GetEvents(pageSize, page, _emptyFilters); // Assert var result = Assert.IsType>>(response); diff --git a/TickAPI/TickAPI.Tests/Events/Filters/EventFilterApplierTests.cs b/TickAPI/TickAPI.Tests/Events/Filters/EventFilterApplierTests.cs new file mode 100644 index 0000000..7657c21 --- /dev/null +++ b/TickAPI/TickAPI.Tests/Events/Filters/EventFilterApplierTests.cs @@ -0,0 +1,669 @@ +using Moq; +using TickAPI.Events.Abstractions; +using TickAPI.Events.DTOs.Request; +using TickAPI.Events.Models; +using TickAPI.Events.Filters; + +namespace TickAPI.Tests.Events.Filters; + +public class EventFilterApplierTests +{ + private readonly Mock _mockEventFilter; + private readonly EventFilterApplier _eventFilterApplier; + private readonly IQueryable _emptyQueryable = new List().AsQueryable(); + + public EventFilterApplierTests() + { + _mockEventFilter = new Mock(); + _mockEventFilter.Setup(ef => ef.GetEvents()).Returns(_emptyQueryable); + _eventFilterApplier = new EventFilterApplier(_mockEventFilter.Object); + } + + [Fact] + public void ApplyFilters_WithName_ShouldCallFilterByName() + { + // Arrange + var filters = new EventFiltersDto( + Name: "test event", + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByName(filters.Name!), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithDescription_ShouldCallFilterByDescription() + { + // Arrange + var filters = new EventFiltersDto( + Name: null, + Descritpion: "test description", + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByDescription(filters.Descritpion!), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithStartDate_ShouldCallFilterByStartDate() + { + // Arrange + var startDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: startDate, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByStartDate(filters.StartDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMinStartDate_ShouldCallFilterByMinStartDate() + { + // Arrange + var minStartDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: minStartDate, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMinStartDate(filters.MinStartDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMaxStartDate_ShouldCallFilterByMaxStartDate() + { + // Arrange + var maxStartDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: maxStartDate, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMaxStartDate(filters.MaxStartDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithEndDate_ShouldCallFilterByEndDate() + { + // Arrange + var endDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: endDate, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByEndDate(filters.EndDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMinEndDate_ShouldCallFilterByMinEndDate() + { + // Arrange + var minEndDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: minEndDate, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMinEndDate(filters.MinEndDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMaxEndDate_ShouldCallFilterByMaxEndDate() + { + // Arrange + var maxEndDate = new DateTime(2025, 5, 1); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: maxEndDate, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMaxEndDate(filters.MaxEndDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMinPrice_ShouldCallFilterByMinPrice() + { + // Arrange + decimal minPrice = 100; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: minPrice, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMinPrice(filters.MinPrice!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMaxPrice_ShouldCallFilterByMaxPrice() + { + // Arrange + decimal maxPrice = 200; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: maxPrice, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMaxPrice(filters.MaxPrice!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMinAge_ShouldCallFilterByMinAge() + { + // Arrange + uint minAge = 18; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: minAge, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMinAge(filters.MinAge!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMaxMinimumAge_ShouldCallFilterByMaxMinimumAge() + { + // Arrange + uint maxMinimumAge = 21; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: maxMinimumAge, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByMaxMinimumAge(filters.MaxMinimumAge!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithAddressCountry_ShouldCallFilterByAddressCountry() + { + // Arrange + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: "Poland", + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByAddressCountry(filters.AddressCountry!), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithAddressCity_ShouldCallFilterByAddressCity() + { + // Arrange + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: "Warsaw", + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByAddressCity(filters.AddressCity!), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithAddressStreetOnly_ShouldCallFilterByAddressStreet() + { + // Arrange + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: "Marszałkowska", + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByAddressStreet(filters.AddressStreet!, null, null), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithAddressStreetAndHouseNumber_ShouldCallFilterByAddressStreet() + { + // Arrange + uint houseNumber = 12; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: "Marszałkowska", + HouseNumber: houseNumber, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByAddressStreet(filters.AddressStreet!, filters.HouseNumber, null), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithCompleteAddress_ShouldCallFilterByAddressStreet() + { + // Arrange + uint houseNumber = 12; + uint flatNumber = 5; + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: "Marszałkowska", + HouseNumber: houseNumber, + FlatNumber: flatNumber + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByAddressStreet(filters.AddressStreet!, filters.HouseNumber, filters.FlatNumber), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithMultipleFilters_ShouldCallAllRelevantFilters() + { + // Arrange + var startDate = new DateTime(2025, 5, 1); + decimal minPrice = 50; + decimal maxPrice = 200; + var filters = new EventFiltersDto( + Name: "Concert", + Descritpion: null, + StartDate: startDate, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: minPrice, + MaxPrice: maxPrice, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: "Poland", + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByName(filters.Name!), Times.Once); + _mockEventFilter.Verify(ef => ef.FilterByStartDate(filters.StartDate!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.FilterByMinPrice(filters.MinPrice!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.FilterByMaxPrice(filters.MaxPrice!.Value), Times.Once); + _mockEventFilter.Verify(ef => ef.FilterByAddressCountry(filters.AddressCountry!), Times.Once); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + } + + [Fact] + public void ApplyFilters_WithNoFilters_ShouldOnlyCallGetEvents() + { + // Arrange + var expectedResult = new List + { + new Event { Name = "Test Event" } + }.AsQueryable(); + _mockEventFilter.Setup(ef => ef.GetEvents()).Returns(expectedResult); + var filters = new EventFiltersDto( + Name: null, + Descritpion: null, + StartDate: null, + MinStartDate: null, + MaxStartDate: null, + EndDate: null, + MinEndDate: null, + MaxEndDate: null, + MinPrice: null, + MaxPrice: null, + MinAge: null, + MaxMinimumAge: null, + AddressCountry: null, + AddressCity: null, + AddressStreet: null, + HouseNumber: null, + FlatNumber: null + ); + + // Act + var result = _eventFilterApplier.ApplyFilters(filters); + + // Assert + _mockEventFilter.Verify(ef => ef.FilterByName(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByDescription(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByStartDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMinStartDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMaxStartDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByEndDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMinEndDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMaxEndDate(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMinPrice(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMaxPrice(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMinAge(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByMaxMinimumAge(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByAddressCountry(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByAddressCity(It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.FilterByAddressStreet(It.IsAny(), It.IsAny(), It.IsAny()), Times.Never); + _mockEventFilter.Verify(ef => ef.GetEvents(), Times.Once); + Assert.Same(expectedResult, result); + } +} \ No newline at end of file diff --git a/TickAPI/TickAPI/Events/Abstractions/IEventFilterApplier.cs b/TickAPI/TickAPI/Events/Abstractions/IEventFilterApplier.cs new file mode 100644 index 0000000..a83432c --- /dev/null +++ b/TickAPI/TickAPI/Events/Abstractions/IEventFilterApplier.cs @@ -0,0 +1,9 @@ +using TickAPI.Events.DTOs.Request; +using TickAPI.Events.Models; + +namespace TickAPI.Events.Abstractions; + +public interface IEventFilterApplier +{ + IQueryable ApplyFilters(EventFiltersDto filters); +} diff --git a/TickAPI/TickAPI/Events/Abstractions/IEventService.cs b/TickAPI/TickAPI/Events/Abstractions/IEventService.cs index 130788c..3b4f020 100644 --- a/TickAPI/TickAPI/Events/Abstractions/IEventService.cs +++ b/TickAPI/TickAPI/Events/Abstractions/IEventService.cs @@ -3,6 +3,7 @@ using TickAPI.Categories.DTOs.Request; using TickAPI.Events.Models; using TickAPI.Common.Results.Generic; +using TickAPI.Events.DTOs.Request; using TickAPI.Events.DTOs.Response; using TickAPI.Organizers.Models; using TickAPI.TicketTypes.DTOs.Request; @@ -14,9 +15,9 @@ public interface IEventService public Task> CreateNewEventAsync(string name, string description, DateTime startDate, DateTime endDate, uint? minimumAge, CreateAddressDto createAddress, List categories, List ticketTypes,EventStatus eventStatus, string organizerEmail); - public Task>> GetOrganizerEventsAsync(Organizer organizer, int page, int pageSize); + public Task>> GetOrganizerEventsAsync(Organizer organizer, int page, int pageSize, EventFiltersDto? eventFilters = null); public Task> GetOrganizerEventsPaginationDetailsAsync(Organizer organizer, int pageSize); - public Task>> GetEventsAsync(int page, int pageSize); + public Task>> GetEventsAsync(int page, int pageSize, EventFiltersDto? eventFilters = null); public Task> GetEventsPaginationDetailsAsync(int pageSize); public Task> GetEventDetailsAsync(Guid eventId); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Events/Controllers/EventsController.cs b/TickAPI/TickAPI/Events/Controllers/EventsController.cs index c27cbcf..c5b3d09 100644 --- a/TickAPI/TickAPI/Events/Controllers/EventsController.cs +++ b/TickAPI/TickAPI/Events/Controllers/EventsController.cs @@ -13,7 +13,6 @@ namespace TickAPI.Events.Controllers; [ApiController] [Route("api/[controller]")] -// TODO: Add lists of categories and tickettypes public class EventsController : ControllerBase { private readonly IEventService _eventService; @@ -50,7 +49,7 @@ public async Task> CreateEvent([FromBody] C [AuthorizeWithPolicy(AuthPolicies.VerifiedOrganizerPolicy)] [HttpGet("organizer")] - public async Task>> GetOrganizerEvents([FromQuery] int pageSize, [FromQuery] int page) + public async Task>> GetOrganizerEvents([FromQuery] int pageSize, [FromQuery] int page, [FromQuery] EventFiltersDto eventFilters) { var emailResult = _claimsService.GetEmailFromClaims(User.Claims); if (emailResult.IsError) @@ -66,7 +65,7 @@ public async Task>> GetOrganizer } var organizer = organizerResult.Value!; - var paginatedDataResult = await _eventService.GetOrganizerEventsAsync(organizer, page, pageSize); + var paginatedDataResult = await _eventService.GetOrganizerEventsAsync(organizer, page, pageSize, eventFilters); if (paginatedDataResult.IsError) { return StatusCode(paginatedDataResult.StatusCode, paginatedDataResult.ErrorMsg); @@ -104,9 +103,9 @@ public async Task> GetOrganizerEventsPaginationD [AuthorizeWithPolicy(AuthPolicies.CustomerPolicy)] [HttpGet] - public async Task>> GetEvents([FromQuery] int pageSize, [FromQuery] int page) + public async Task>> GetEvents([FromQuery] int pageSize, [FromQuery] int page, [FromQuery] EventFiltersDto eventFilters) { - var paginatedDataResult = await _eventService.GetEventsAsync(page, pageSize); + var paginatedDataResult = await _eventService.GetEventsAsync(page, pageSize, eventFilters); if (paginatedDataResult.IsError) { return StatusCode(paginatedDataResult.StatusCode, paginatedDataResult.ErrorMsg); diff --git a/TickAPI/TickAPI/Events/DTOs/Request/EventFiltersDto.cs b/TickAPI/TickAPI/Events/DTOs/Request/EventFiltersDto.cs new file mode 100644 index 0000000..91e52cc --- /dev/null +++ b/TickAPI/TickAPI/Events/DTOs/Request/EventFiltersDto.cs @@ -0,0 +1,21 @@ +namespace TickAPI.Events.DTOs.Request; + +public record EventFiltersDto( + string? Name, + string? Descritpion, + DateTime? StartDate, + DateTime? MinStartDate, + DateTime? MaxStartDate, + DateTime? EndDate, + DateTime? MinEndDate, + DateTime? MaxEndDate, + decimal? MinPrice, + decimal? MaxPrice, + uint? MinAge, + uint? MaxMinimumAge, + string? AddressCountry, + string? AddressCity, + string? AddressStreet, + uint? HouseNumber, + uint? FlatNumber +); diff --git a/TickAPI/TickAPI/Events/Filters/EventFilter.cs b/TickAPI/TickAPI/Events/Filters/EventFilter.cs index 1a4a3d5..0e0f017 100644 --- a/TickAPI/TickAPI/Events/Filters/EventFilter.cs +++ b/TickAPI/TickAPI/Events/Filters/EventFilter.cs @@ -19,12 +19,12 @@ public IQueryable GetEvents() public void FilterByName(string name) { - _events = _events.Where(e => e.Name.Contains(name, StringComparison.CurrentCultureIgnoreCase)); + _events = _events.Where(e => e.Name.ToLower().Contains(name.ToLower())); } public void FilterByDescription(string description) { - _events = _events.Where(e => e.Description.Contains(description, StringComparison.CurrentCultureIgnoreCase)); + _events = _events.Where(e => e.Description.ToLower().Contains(description.ToLower())); } public void FilterByStartDate(DateTime startDate) @@ -79,17 +79,17 @@ public void FilterByMaxMinimumAge(uint maxMinimumAge) public void FilterByAddressCountry(string country) { - _events = _events.Where(e => e.Address.Country.Contains(country, StringComparison.CurrentCultureIgnoreCase)); + _events = _events.Where(e => e.Address.Country.ToLower().Contains(country.ToLower())); } public void FilterByAddressCity(string city) { - _events = _events.Where(e => e.Address.City.Contains(city, StringComparison.CurrentCultureIgnoreCase)); + _events = _events.Where(e => e.Address.City.ToLower().Contains(city.ToLower())); } public void FilterByAddressStreet(string street, uint? houseNumber = null, uint? flatNumber = null) { - var result = _events.Where(e => e.Address.Street != null && e.Address.Street.Contains(street, StringComparison.CurrentCultureIgnoreCase)); + var result = _events.Where(e => e.Address.Street != null && e.Address.Street.ToLower().Contains(street.ToLower())); if (houseNumber != null) { result = result.Where(e => e.Address.HouseNumber != null && e.Address.HouseNumber == houseNumber); diff --git a/TickAPI/TickAPI/Events/Filters/EventFilterApplier.cs b/TickAPI/TickAPI/Events/Filters/EventFilterApplier.cs new file mode 100644 index 0000000..7347465 --- /dev/null +++ b/TickAPI/TickAPI/Events/Filters/EventFilterApplier.cs @@ -0,0 +1,50 @@ +using TickAPI.Events.Abstractions; +using TickAPI.Events.DTOs.Request; +using TickAPI.Events.Models; + +namespace TickAPI.Events.Filters; + +public class EventFilterApplier : IEventFilterApplier +{ + private readonly IEventFilter _eventFilter; + private readonly Dictionary, Action> _filterActions; + + public EventFilterApplier(IEventFilter eventFilter) + { + _eventFilter = eventFilter; + _filterActions = new Dictionary, Action> + { + { f => !string.IsNullOrEmpty(f.Name), f => _eventFilter.FilterByName(f.Name!) }, + { f => !string.IsNullOrEmpty(f.Descritpion), f => _eventFilter.FilterByDescription(f.Descritpion!) }, + { f => f.StartDate.HasValue, f => _eventFilter.FilterByStartDate(f.StartDate!.Value) }, + { f => f.MinStartDate.HasValue, f => _eventFilter.FilterByMinStartDate(f.MinStartDate!.Value) }, + { f => f.MaxStartDate.HasValue, f => _eventFilter.FilterByMaxStartDate(f.MaxStartDate!.Value) }, + { f => f.EndDate.HasValue, f => _eventFilter.FilterByEndDate(f.EndDate!.Value) }, + { f => f.MinEndDate.HasValue, f => _eventFilter.FilterByMinEndDate(f.MinEndDate!.Value) }, + { f => f.MaxEndDate.HasValue, f => _eventFilter.FilterByMaxEndDate(f.MaxEndDate!.Value) }, + { f => f.MinPrice.HasValue, f => _eventFilter.FilterByMinPrice(f.MinPrice!.Value) }, + { f => f.MaxPrice.HasValue, f => _eventFilter.FilterByMaxPrice(f.MaxPrice!.Value) }, + { f => f.MinAge.HasValue, f => _eventFilter.FilterByMinAge(f.MinAge!.Value) }, + { f => f.MaxMinimumAge.HasValue, f => _eventFilter.FilterByMaxMinimumAge(f.MaxMinimumAge!.Value) }, + { f => !string.IsNullOrEmpty(f.AddressCountry), f => _eventFilter.FilterByAddressCountry(f.AddressCountry!) }, + { f => !string.IsNullOrEmpty(f.AddressCity), f => _eventFilter.FilterByAddressCity(f.AddressCity!) }, + { f => !string.IsNullOrEmpty(f.AddressStreet), f => _eventFilter.FilterByAddressStreet( + f.AddressStreet!, + f.HouseNumber, + f.FlatNumber) } + }; + } + + public IQueryable ApplyFilters(EventFiltersDto filters) + { + foreach (var (condition, apply) in _filterActions) + { + if (condition(filters)) + { + apply(filters); + } + } + + return _eventFilter.GetEvents(); + } +} diff --git a/TickAPI/TickAPI/Events/Services/EventService.cs b/TickAPI/TickAPI/Events/Services/EventService.cs index d0c5244..201a9a9 100644 --- a/TickAPI/TickAPI/Events/Services/EventService.cs +++ b/TickAPI/TickAPI/Events/Services/EventService.cs @@ -8,7 +8,9 @@ using TickAPI.Events.Abstractions; using TickAPI.Events.Models; using TickAPI.Common.Results.Generic; +using TickAPI.Events.DTOs.Request; using TickAPI.Events.DTOs.Response; +using TickAPI.Events.Filters; using TickAPI.Organizers.Abstractions; using TickAPI.Organizers.Models; using TickAPI.Tickets.Abstractions; @@ -96,10 +98,11 @@ public async Task> CreateNewEventAsync(string name, string descri return Result.Success(@event); } - public async Task>> GetOrganizerEventsAsync(Organizer organizer, int page, int pageSize) + public async Task>> GetOrganizerEventsAsync(Organizer organizer, int page, int pageSize, EventFiltersDto? eventFilters = null) { var organizerEvents = _eventRepository.GetEventsByOranizer(organizer); - return await GetPaginatedEventsAsync(organizerEvents, page, pageSize); + var filteredOrganizerEvents = ApplyEventFilters(organizerEvents, eventFilters); + return await GetPaginatedEventsAsync(filteredOrganizerEvents, page, pageSize); } public async Task> GetOrganizerEventsPaginationDetailsAsync(Organizer organizer, int pageSize) @@ -108,10 +111,11 @@ public async Task> GetOrganizerEventsPaginationDetails return await _paginationService.GetPaginationDetailsAsync(organizerEvents, pageSize); } - public async Task>> GetEventsAsync(int page, int pageSize) + public async Task>> GetEventsAsync(int page, int pageSize, EventFiltersDto? eventFilters = null) { var events = _eventRepository.GetEvents(); - return await GetPaginatedEventsAsync(events, page, pageSize); + var filteredEvents = ApplyEventFilters(events, eventFilters); + return await GetPaginatedEventsAsync(filteredEvents, page, pageSize); } public async Task> GetEventsPaginationDetailsAsync(int pageSize) @@ -171,6 +175,18 @@ private async Task>> GetPaginatedEvent return Result>.Success(paginatedData); } + + private IQueryable ApplyEventFilters(IQueryable events, EventFiltersDto? eventFilters = null) + { + if (eventFilters is null) + { + return events; + } + var ef = new EventFilter(events); + var eventFiltersApplier = new EventFilterApplier(ef); + var filteredEvents = eventFiltersApplier.ApplyFilters(eventFilters); + return filteredEvents; + } private static GetEventResponseDto MapEventToGetEventResponseDto(Event ev) { diff --git a/TickAPI/TickAPI/Program.cs b/TickAPI/TickAPI/Program.cs index 40523e4..a979010 100644 --- a/TickAPI/TickAPI/Program.cs +++ b/TickAPI/TickAPI/Program.cs @@ -1,5 +1,4 @@ using System.Text; -using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore;