diff --git a/TickAPI/TickAPI.Tests/Events/Controllers/EventControllerTests.cs b/TickAPI/TickAPI.Tests/Events/Controllers/EventControllerTests.cs index 8c788b1..c0789fa 100644 --- a/TickAPI/TickAPI.Tests/Events/Controllers/EventControllerTests.cs +++ b/TickAPI/TickAPI.Tests/Events/Controllers/EventControllerTests.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using TickAPI.Addresses.DTOs.Request; +using TickAPI.Categories.DTOs.Request; using TickAPI.Common.Claims.Abstractions; using TickAPI.Common.Pagination.Responses; using TickAPI.Events.Controllers; @@ -13,6 +14,7 @@ using TickAPI.Events.DTOs.Response; using TickAPI.Organizers.Abstractions; using TickAPI.Organizers.Models; +using TickAPI.TicketTypes.DTOs.Request; namespace TickAPI.Tests.Events.Controllers; @@ -30,12 +32,22 @@ public async Task CreateEvent_WhenDataIsValid_ShouldReturnSuccess() const string email = "123@mail.com"; const EventStatus eventStatus = EventStatus.TicketsAvailable; Guid id = Guid.NewGuid(); + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 5, 10)), + ]; CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); - CreateEventDto eventDto = new CreateEventDto(name, description, startDate, endDate, minimumAge, eventStatus, createAddress); + CreateEventDto eventDto = new CreateEventDto(name, description, startDate, endDate, minimumAge, categories, ticketTypes, eventStatus, createAddress); var eventServiceMock = new Mock(); eventServiceMock - .Setup(m => m.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, eventStatus, email)) + .Setup(m => m.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, categories , ticketTypes, eventStatus, email)) .ReturnsAsync(Result.Success(new Event())); var claims = new List @@ -79,6 +91,17 @@ public async Task CreateEvent_WhenMissingEmailClaims_ShouldReturnBadRequest() DateTime endDate = new DateTime(2025, 6, 1); uint? minimumAge = 18; const EventStatus eventStatus = EventStatus.TicketsAvailable; + string email = "123@mail.com"; + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 5, 10)), + ]; CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); var eventServiceMock = new Mock(); @@ -97,8 +120,8 @@ public async Task CreateEvent_WhenMissingEmailClaims_ShouldReturnBadRequest() } }; - // Act - var res = await sut.CreateEvent(new CreateEventDto(name, description, startDate, endDate, minimumAge, eventStatus, createAddress)); + // act + var res = await sut.CreateEvent(new CreateEventDto(name, description, startDate, endDate, minimumAge, categories, ticketTypes, eventStatus, createAddress)); // Assert var result = Assert.IsType>(res); diff --git a/TickAPI/TickAPI.Tests/Events/Services/EventServiceTests.cs b/TickAPI/TickAPI.Tests/Events/Services/EventServiceTests.cs index 59bdd8a..0989a18 100644 --- a/TickAPI/TickAPI.Tests/Events/Services/EventServiceTests.cs +++ b/TickAPI/TickAPI.Tests/Events/Services/EventServiceTests.cs @@ -6,6 +6,9 @@ using TickAPI.Addresses.Models; using TickAPI.Common.Pagination.Abstractions; using TickAPI.Common.Pagination.Responses; +using TickAPI.Categories.Abstractions; +using TickAPI.Categories.DTOs.Request; +using TickAPI.Categories.Models; using TickAPI.Events.Models; using TickAPI.Organizers.Abstractions; using TickAPI.Organizers.Models; @@ -13,6 +16,8 @@ using TickAPI.Common.Time.Abstractions; using TickAPI.Events.DTOs.Response; using TickAPI.Events.Services; +using TickAPI.TicketTypes.DTOs.Request; +using TickAPI.TicketTypes.Models; namespace TickAPI.Tests.Events.Services; @@ -31,6 +36,47 @@ public async Task CreateNewEventAsync_WhenEventDataIsValid_ShouldReturnNewEvent( string organizerEmail = "123@mail.com"; EventStatus eventStatus = EventStatus.TicketsAvailable; Guid id = Guid.NewGuid(); + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List expectedCategories = + [ + new Category + { + Name = "concert", + }, + new Category + { + Name = "bear metal", + } + + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 5, 10)), + ]; + List expectedTicketTypes = + [ + new TicketType + { + Description = "normal", + MaxCount = 100, + Price = 50.9m, + Currency = "zł", + AvailableFrom = new DateTime(2025, 5, 1) + }, + new TicketType + { + Description = "V.I.P", + MaxCount = 10, + Price = 500.9m, + Currency = "zł", + AvailableFrom = new DateTime(2025, 5, 10) + }, + ]; CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); var eventRepositoryMock = new Mock(); @@ -57,13 +103,15 @@ public async Task CreateNewEventAsync_WhenEventDataIsValid_ShouldReturnNewEvent( var dateTimeServiceMock = new Mock(); dateTimeServiceMock.Setup(m => m.GetCurrentDateTime()).Returns(new DateTime(2003, 7, 11)); + + var categoryServiceMock = new Mock(); + categoryServiceMock.Setup(c => c.CheckIfCategoriesExistAsync(It.IsAny>())).Returns(Task.FromResult(true)); var paginationServiceMock = new Mock(); - - var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object); + var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act - var result = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, eventStatus, organizerEmail); + var result = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, categories, ticketTypes, eventStatus, organizerEmail); // Assert Assert.True(result.IsSuccess); @@ -74,6 +122,22 @@ public async Task CreateNewEventAsync_WhenEventDataIsValid_ShouldReturnNewEvent( Assert.Equal(eventStatus, result.Value!.EventStatus); Assert.Equal(id, result.Value!.Id); Assert.Equal(organizerEmail, result.Value!.Organizer.Email); + Assert.Equal(expectedCategories.Count, result.Value!.Categories.Count); + foreach (var expectedCategory in expectedCategories) + { + Assert.Contains(result.Value!.Categories, actualCategory => + actualCategory.Name == expectedCategory.Name); + } + Assert.Equal(expectedTicketTypes.Count, result.Value!.TicketTypes.Count); + foreach (var expectedTicketType in expectedTicketTypes) + { + Assert.Contains(result.Value!.TicketTypes, actualTicketType => + actualTicketType.Description == expectedTicketType.Description && + actualTicketType.MaxCount == expectedTicketType.MaxCount && + actualTicketType.Price == expectedTicketType.Price && + actualTicketType.Currency == expectedTicketType.Currency && + actualTicketType.AvailableFrom == expectedTicketType.AvailableFrom); + } } [Fact] @@ -88,6 +152,16 @@ public async Task CreateNewEventAsync_WhenEndDateIsBeforeStartDate_ShouldReturnB string organizerEmail = "123@mail.com"; EventStatus eventStatus = EventStatus.TicketsAvailable; Guid id = Guid.NewGuid(); + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 5, 10)), + ]; CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); var eventRepositoryMock = new Mock(); @@ -100,13 +174,16 @@ public async Task CreateNewEventAsync_WhenEndDateIsBeforeStartDate_ShouldReturnB var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); - - var paginationServiceMock = new Mock(); - var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object); + var categoryServiceMock = new Mock(); + // Act - var res = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, eventStatus, organizerEmail); + var paginationServiceMock = new Mock(); + + var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); + + var res = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, categories, ticketTypes, eventStatus, organizerEmail); // Assert Assert.False(res.IsSuccess); @@ -114,6 +191,57 @@ public async Task CreateNewEventAsync_WhenEndDateIsBeforeStartDate_ShouldReturnB Assert.Equal("End date should be after start date", res.ErrorMsg); } + [Fact] + public async Task CreateNewEventAsync_WhenTicketTypeAvailabilityIsAfterEventsEnd_ShouldReturnBadRequest() + { + // Arrange + string name = "Concert"; + string description = "Description of a concert"; + DateTime startDate = new DateTime(2025, 5, 1); + DateTime endDate = new DateTime(2025, 6, 1); + uint? minimumAge = 18; + string organizerEmail = "123@mail.com"; + EventStatus eventStatus = EventStatus.TicketsAvailable; + Guid id = Guid.NewGuid(); + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 6, 10)), + ]; + CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); + + var eventRepositoryMock = new Mock(); + + var organizerServiceMock = new Mock(); + organizerServiceMock + .Setup(m => m.GetOrganizerByEmailAsync(organizerEmail)) + .ReturnsAsync(Result.Success(new Organizer { Email = organizerEmail, IsVerified = true })); + + var addressServiceMock = new Mock(); + + var dateTimeServiceMock = new Mock(); + dateTimeServiceMock.Setup(m => m.GetCurrentDateTime()).Returns(new DateTime(2025, 4, 11)); + + var categoryServiceMock = new Mock(); + + // Act + var paginationServiceMock = new Mock(); + + var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); + + var res = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, categories, ticketTypes, eventStatus, organizerEmail); + + // Assert + Assert.False(res.IsSuccess); + Assert.Equal(StatusCodes.Status400BadRequest, res.StatusCode); + Assert.Equal("Tickets can't be available after the event is over", res.ErrorMsg); + } + [Fact] public async Task CreateNewEventAsync_WhenStartDateIsBeforeNow_ShouldReturnBadRequest() { @@ -125,6 +253,17 @@ public async Task CreateNewEventAsync_WhenStartDateIsBeforeNow_ShouldReturnBadRe uint? minimumAge = 18; string organizerEmail = "123@mail.com"; EventStatus eventStatus = EventStatus.TicketsAvailable; + Guid id = Guid.NewGuid(); + List categories = + [ + new CreateEventCategoryDto("concert"), + new CreateEventCategoryDto("bear metal") + ]; + List ticketTypes = + [ + new CreateEventTicketTypeDto("normal", 100, 50.9m, "zł", new DateTime(2025, 5, 1)), + new CreateEventTicketTypeDto("V.I.P", 10, 500.9m, "zł", new DateTime(2025, 5, 10)), + ]; CreateAddressDto createAddress = new CreateAddressDto("United States", "New York", "Main st", 20, null, "00-000"); var eventRepositoryMock = new Mock(); @@ -138,13 +277,15 @@ public async Task CreateNewEventAsync_WhenStartDateIsBeforeNow_ShouldReturnBadRe var dateTimeServiceMock = new Mock(); dateTimeServiceMock.Setup(m => m.GetCurrentDateTime()).Returns(new DateTime(2025, 5, 11)); - - var paginationServiceMock = new Mock(); - var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object); + var categoryServiceMock = new Mock(); // Act - var res = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, eventStatus, organizerEmail); + var paginationServiceMock = new Mock(); + + var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); + + var res = await sut.CreateNewEventAsync(name, description, startDate, endDate, minimumAge, createAddress, categories, ticketTypes, eventStatus, organizerEmail); // Assert Assert.False(res.IsSuccess); @@ -175,6 +316,7 @@ public async Task GetOrganizerEvents_WhenPaginationSucceeds_ShouldReturnPaginate var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var paginatedEvents = new PaginatedData( organizer.Events.Take(pageSize).ToList(), @@ -208,7 +350,7 @@ public async Task GetOrganizerEvents_WhenPaginationSucceeds_ShouldReturnPaginate )); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetOrganizerEventsAsync(organizer, page, pageSize); @@ -248,6 +390,7 @@ public async Task GetOrganizerEvents_WhenPaginationFails_ShouldPropagateError() var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var organizerEvents = organizer.Events.AsQueryable(); eventRepositoryMock.Setup(p => p.GetEventsByOranizer(organizer)).Returns(organizerEvents); @@ -257,7 +400,7 @@ public async Task GetOrganizerEvents_WhenPaginationFails_ShouldPropagateError() .ReturnsAsync(Result>.Failure(StatusCodes.Status400BadRequest, "Invalid page number")); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetOrganizerEventsAsync(organizer, page, pageSize); @@ -286,6 +429,7 @@ public async Task GetEventsAsync_WhenPaginationSucceeds_ShouldReturnPaginatedEve var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var paginatedEvents = new PaginatedData( events.Take(pageSize).ToList(), @@ -319,7 +463,7 @@ public async Task GetEventsAsync_WhenPaginationSucceeds_ShouldReturnPaginatedEve )); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetEventsAsync(page, pageSize); @@ -354,6 +498,7 @@ public async Task GetEventsAsync_WhenPaginationFails_ShouldPropagateError() var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var eventsQueryable = events.AsQueryable(); eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable); @@ -363,7 +508,7 @@ public async Task GetEventsAsync_WhenPaginationFails_ShouldPropagateError() .ReturnsAsync(Result>.Failure(StatusCodes.Status400BadRequest, "Invalid page number")); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetEventsAsync(page, pageSize); @@ -391,6 +536,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenSuccessful_ShouldReturnPag var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var eventsQueryable = events.AsQueryable(); eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable); @@ -401,7 +547,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenSuccessful_ShouldReturnPag .ReturnsAsync(Result.Success(paginationDetails)); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetEventsPaginationDetailsAsync(pageSize); @@ -428,6 +574,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenFails_ShouldReturnError() var addressServiceMock = new Mock(); var dateTimeServiceMock = new Mock(); var paginationServiceMock = new Mock(); + var categoryServiceMock = new Mock(); var eventsQueryable = events.AsQueryable(); eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable); @@ -437,7 +584,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenFails_ShouldReturnError() .ReturnsAsync(Result.Failure(StatusCodes.Status400BadRequest, "Invalid page size")); var sut = new EventService(eventRepositoryMock.Object, organizerServiceMock.Object, addressServiceMock.Object, - dateTimeServiceMock.Object, paginationServiceMock.Object); + dateTimeServiceMock.Object, paginationServiceMock.Object, categoryServiceMock.Object); // Act var result = await sut.GetEventsPaginationDetailsAsync(pageSize); diff --git a/TickAPI/TickAPI/Categories/Abstractions/ICategoryService.cs b/TickAPI/TickAPI/Categories/Abstractions/ICategoryService.cs index 0e33bf0..8560738 100644 --- a/TickAPI/TickAPI/Categories/Abstractions/ICategoryService.cs +++ b/TickAPI/TickAPI/Categories/Abstractions/ICategoryService.cs @@ -10,4 +10,6 @@ public interface ICategoryService public Task> GetCategoryByNameAsync(string categoryName); public Task>> GetCategoriesResponsesAsync(int pageSize, int page); public Task> CreateNewCategoryAsync(string categoryName); + + public Task CheckIfCategoriesExistAsync(IEnumerable categories); } \ No newline at end of file diff --git a/TickAPI/TickAPI/Categories/DTOs/CreateCategoryDto.cs b/TickAPI/TickAPI/Categories/DTOs/Request/CreateCategoryDto.cs similarity index 100% rename from TickAPI/TickAPI/Categories/DTOs/CreateCategoryDto.cs rename to TickAPI/TickAPI/Categories/DTOs/Request/CreateCategoryDto.cs diff --git a/TickAPI/TickAPI/Categories/DTOs/Request/CreateEventCategoryDto.cs b/TickAPI/TickAPI/Categories/DTOs/Request/CreateEventCategoryDto.cs new file mode 100644 index 0000000..8e696d7 --- /dev/null +++ b/TickAPI/TickAPI/Categories/DTOs/Request/CreateEventCategoryDto.cs @@ -0,0 +1,6 @@ +namespace TickAPI.Categories.DTOs.Request; + +public record CreateEventCategoryDto +( + string CategoryName +); \ No newline at end of file diff --git a/TickAPI/TickAPI/Categories/Services/CategoryService.cs b/TickAPI/TickAPI/Categories/Services/CategoryService.cs index 929c99e..e30dafc 100644 --- a/TickAPI/TickAPI/Categories/Services/CategoryService.cs +++ b/TickAPI/TickAPI/Categories/Services/CategoryService.cs @@ -1,4 +1,5 @@ -using TickAPI.Categories.Abstractions; +using Microsoft.EntityFrameworkCore; +using TickAPI.Categories.Abstractions; using TickAPI.Categories.DTOs.Response; using TickAPI.Categories.Models; using TickAPI.Common.Pagination.Abstractions; @@ -55,4 +56,11 @@ public async Task> CreateNewCategoryAsync(string categoryName) await _categoryRepository.AddNewCategoryAsync(category); return Result.Success(category); } + + public async Task CheckIfCategoriesExistAsync(IEnumerable categories) + { + var dbCategories = _categoryRepository.GetCategories(); + int count = await dbCategories.Where(cdb => categories.Any(c => c.Name == cdb.Name)).CountAsync(); + return count == categories.Count(); + } } \ No newline at end of file diff --git a/TickAPI/TickAPI/Events/Abstractions/IEventService.cs b/TickAPI/TickAPI/Events/Abstractions/IEventService.cs index 8afbaad..465defd 100644 --- a/TickAPI/TickAPI/Events/Abstractions/IEventService.cs +++ b/TickAPI/TickAPI/Events/Abstractions/IEventService.cs @@ -1,16 +1,19 @@ using TickAPI.Addresses.DTOs.Request; using TickAPI.Common.Pagination.Responses; +using TickAPI.Categories.DTOs.Request; using TickAPI.Events.Models; using TickAPI.Common.Results.Generic; using TickAPI.Events.DTOs.Response; using TickAPI.Organizers.Models; +using TickAPI.TicketTypes.DTOs.Request; namespace TickAPI.Events.Abstractions; public interface IEventService { public Task> CreateNewEventAsync(string name, string description, DateTime startDate, - DateTime endDate, uint? minimumAge, CreateAddressDto createAddress, EventStatus eventStatus, string organizerEmail); + 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> GetOrganizerEventsPaginationDetailsAsync(Organizer organizer, int pageSize); public Task>> GetEventsAsync(int page, int pageSize); diff --git a/TickAPI/TickAPI/Events/Controllers/EventController.cs b/TickAPI/TickAPI/Events/Controllers/EventController.cs index 5ea6f4e..27594f7 100644 --- a/TickAPI/TickAPI/Events/Controllers/EventController.cs +++ b/TickAPI/TickAPI/Events/Controllers/EventController.cs @@ -38,7 +38,9 @@ public async Task> CreateEvent([FromBody] C } var email = emailResult.Value!; - var newEventResult = await _eventService.CreateNewEventAsync(request.Name, request.Description, request.StartDate, request.EndDate, request.MinimumAge, request.CreateAddress, request.EventStatus, email); + var newEventResult = await _eventService.CreateNewEventAsync(request.Name, request.Description, + request.StartDate, request.EndDate, request.MinimumAge, request.CreateAddress, request.Categories + , request.TicketTypes ,request.EventStatus, email); if (newEventResult.IsError) return StatusCode(newEventResult.StatusCode, newEventResult.ErrorMsg); diff --git a/TickAPI/TickAPI/Events/DTOs/Request/CreateEventDto.cs b/TickAPI/TickAPI/Events/DTOs/Request/CreateEventDto.cs index 1078587..5b6f447 100644 --- a/TickAPI/TickAPI/Events/DTOs/Request/CreateEventDto.cs +++ b/TickAPI/TickAPI/Events/DTOs/Request/CreateEventDto.cs @@ -1,15 +1,18 @@ using TickAPI.Events.Models; using TickAPI.Addresses.DTOs.Request; +using TickAPI.Categories.DTOs.Request; +using TickAPI.TicketTypes.DTOs.Request; namespace TickAPI.Events.DTOs.Request; -public record CreateEventDto -( +public record CreateEventDto( string Name, string Description, DateTime StartDate, DateTime EndDate, uint? MinimumAge, + List Categories, + List TicketTypes, EventStatus EventStatus, CreateAddressDto CreateAddress ); \ No newline at end of file diff --git a/TickAPI/TickAPI/Events/Services/EventService.cs b/TickAPI/TickAPI/Events/Services/EventService.cs index 6ac130c..117c7eb 100644 --- a/TickAPI/TickAPI/Events/Services/EventService.cs +++ b/TickAPI/TickAPI/Events/Services/EventService.cs @@ -2,6 +2,9 @@ using TickAPI.Addresses.DTOs.Request; using TickAPI.Common.Pagination.Abstractions; using TickAPI.Common.Pagination.Responses; +using TickAPI.Categories.Abstractions; +using TickAPI.Categories.DTOs.Request; +using TickAPI.Categories.Models; using TickAPI.Common.Time.Abstractions; using TickAPI.Events.Abstractions; using TickAPI.Events.Models; @@ -9,6 +12,8 @@ using TickAPI.Events.DTOs.Response; using TickAPI.Organizers.Abstractions; using TickAPI.Organizers.Models; +using TickAPI.TicketTypes.DTOs.Request; +using TickAPI.TicketTypes.Models; namespace TickAPI.Events.Services; @@ -19,17 +24,21 @@ public class EventService : IEventService private readonly IAddressService _addressService; private readonly IDateTimeService _dateTimeService; private readonly IPaginationService _paginationService; + private readonly ICategoryService _categoryService; - public EventService(IEventRepository eventRepository, IOrganizerService organizerService, IAddressService addressService, IDateTimeService dateTimeService, IPaginationService paginationService) + public EventService(IEventRepository eventRepository, IOrganizerService organizerService, IAddressService addressService, IDateTimeService dateTimeService, IPaginationService paginationService, ICategoryService categoryService) { _eventRepository = eventRepository; _organizerService = organizerService; _addressService = addressService; _dateTimeService = dateTimeService; _paginationService = paginationService; + _categoryService = categoryService; } - public async Task> CreateNewEventAsync(string name, string description, DateTime startDate, DateTime endDate, uint? minimumAge, CreateAddressDto createAddress, EventStatus eventStatus, string organizerEmail) + public async Task> CreateNewEventAsync(string name, string description, DateTime startDate, DateTime endDate, + uint? minimumAge, CreateAddressDto createAddress, List categories, List ticketTypes, + EventStatus eventStatus, string organizerEmail) { var organizerResult = await _organizerService.GetOrganizerByEmailAsync(organizerEmail); if (!organizerResult.IsSuccess) @@ -41,10 +50,32 @@ public async Task> CreateNewEventAsync(string name, string descri if (startDate < _dateTimeService.GetCurrentDateTime()) return Result.Failure(StatusCodes.Status400BadRequest, "Start date is in the past"); - + + if (ticketTypes.Any(t => t.AvailableFrom > endDate)) + { + return Result.Failure(StatusCodes.Status400BadRequest, "Tickets can't be available after the event is over"); + } var address = await _addressService.GetOrCreateAddressAsync(createAddress); - + + var categoriesConverted = categories.Select(c => new Category { Name = c.CategoryName }).ToList(); + + var categoriesExist = await _categoryService.CheckIfCategoriesExistAsync(categoriesConverted); + if (!categoriesExist) + { + return Result.Failure(StatusCodes.Status400BadRequest, "Category does not exist"); + } + + var ticketTypesConverted = ticketTypes.Select(t => new TicketType + { + Description = t.Description, + AvailableFrom = t.AvailableFrom, + Currency = t.Currency, + MaxCount = t.MaxCount, + Price = t.Price, + }) + .ToList(); + var @event = new Event { Name = name, @@ -53,8 +84,10 @@ public async Task> CreateNewEventAsync(string name, string descri EndDate = endDate, MinimumAge = minimumAge, Address = address.Value!, + Categories = categoriesConverted, Organizer = organizerResult.Value!, - EventStatus = eventStatus + EventStatus = eventStatus, + TicketTypes = ticketTypesConverted, }; await _eventRepository.AddNewEventAsync(@event); return Result.Success(@event); @@ -99,7 +132,7 @@ private async Task>> GetPaginatedEvent private static GetEventResponseDto MapEventToGetEventResponseDto(Event ev) { - var categories = ev.Categories.Select((c) => new GetEventResponseCategoryDto(c.Name)).ToList(); + var categories = ev.Categories.Count > 0 ? ev.Categories.Select((c) => new GetEventResponseCategoryDto(c.Name)).ToList() : new List(); var address = new GetEventResponseAddressDto(ev.Address.Country, ev.Address.City, ev.Address.PostalCode, ev.Address.Street, ev.Address.HouseNumber, ev.Address.FlatNumber); return new GetEventResponseDto(ev.Name, ev.Description, ev.StartDate, ev.EndDate, ev.MinimumAge, categories, ev.EventStatus, address); } diff --git a/TickAPI/TickAPI/TicketTypes/DTOs/Request/CreateAddressTicketTypeDto.cs b/TickAPI/TickAPI/TicketTypes/DTOs/Request/CreateAddressTicketTypeDto.cs new file mode 100644 index 0000000..96a002c --- /dev/null +++ b/TickAPI/TickAPI/TicketTypes/DTOs/Request/CreateAddressTicketTypeDto.cs @@ -0,0 +1,9 @@ +namespace TickAPI.TicketTypes.DTOs.Request; + +public record CreateEventTicketTypeDto( + string Description, + uint MaxCount, + decimal Price, + string Currency, + DateTime AvailableFrom + ); \ No newline at end of file