Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Moq;
using TickAPI.Addresses.Models;
using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Results.Generic;
using TickAPI.Customers.Models;
using TickAPI.Events.Models;
using TickAPI.Organizers.Models;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.Tickets.Models;
Expand Down Expand Up @@ -326,4 +331,107 @@ public async Task GetTicketsForResellAsync_WhenNoTicketsForEvent_ShouldReturnEmp
Assert.True(result.IsSuccess);
Assert.Empty(result.Value!.Data);
}

[Fact]
public async Task GetTicketDetailsAsync_WhenTicketExistsForTheUser_ShouldReturnTicketDetails()
{

// Arrange
var eventGuid = Guid.NewGuid();
var ticket = new Ticket
{
Id = Guid.NewGuid(),
ForResell = false,
NameOnTicket = "NameOnTicket",
Seats = null,
Type = new TicketType
{
Id = eventGuid,
Currency = "USD",
Price = 20,
Event = new Event
{
Name = "EventName",
StartDate = new DateTime(2025, 10, 10),
EndDate = new DateTime(2025, 10, 20),
Organizer = new Organizer
{
DisplayName = "organizerName",
},
Address = new Address
{
City = "Warsaw",
Country = "Poland",
PostalCode = "12345",
FlatNumber = null,
HouseNumber = null,
Street = "Street",
}
}
},
};
string email = "123@123.com";

Mock<ITicketRepository> ticketRepositoryMock = new Mock<ITicketRepository>();

var paginationServiceMock = new Mock<IPaginationService>();

ticketRepositoryMock.Setup(m => m.GetTicketWithDetailsByIdAndEmailAsync(ticket.Id, email))
.ReturnsAsync(Result<Ticket>.Success(ticket));

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act

var res = await sut.GetTicketDetailsAsync(ticket.Id, email);

// Assert

Assert.True(res.IsSuccess);
var details = res.Value;
Assert.NotNull(details);

Assert.Equal(ticket.NameOnTicket, details.NameOnTicket);
Assert.Equal(ticket.Seats, details.Seats);
Assert.Equal(ticket.Type.Currency, details.Currency);
Assert.Equal(ticket.Type.Price, details.Price);
Assert.Equal(ticket.Type.Event.StartDate, details.StartDate);
Assert.Equal(ticket.Type.Event.EndDate, details.EndDate);
Assert.Equal(ticket.Type.Event.Organizer.DisplayName, details.OrganizerName);
Assert.Equal(ticket.Type.Event.Address.Street, details.Address.Street);
Assert.Equal(ticket.Type.Event.Address.HouseNumber, details.Address.HouseNumber);
Assert.Equal(ticket.Type.Event.Address.FlatNumber, details.Address.FlatNumber);
Assert.Equal(ticket.Type.Event.Address.PostalCode, details.Address.PostalCode);
Assert.Equal(ticket.Type.Event.Address.City, details.Address.City);
Assert.Equal(ticket.Type.Event.Address.Country, details.Address.Country);

}

[Fact]
public async Task GetTicketDetailsAsync_WhenTicketDoesNotExistForTheUser_ShouldReturnError()
{

// Arrange

Guid ticketId = Guid.NewGuid();
string email = "123@123.com";

Mock<ITicketRepository> ticketRepositoryMock = new Mock<ITicketRepository>();
ticketRepositoryMock.Setup(m => m.GetTicketWithDetailsByIdAndEmailAsync(ticketId, email)).
ReturnsAsync(Result<Ticket>.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist " +
"for this user"));
var paginationServiceMock = new Mock<IPaginationService>();

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act

var res = await sut.GetTicketDetailsAsync(ticketId, email);

// Assert

Assert.False(res.IsSuccess);
Assert.Equal(StatusCodes.Status404NotFound, res.StatusCode);
Assert.Equal("Ticket with this id doesn't exist for this user", res.ErrorMsg);
}
}
4 changes: 3 additions & 1 deletion TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using TickAPI.Tickets.Models;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.Models;
using TickAPI.TicketTypes.Models;

namespace TickAPI.Tickets.Abstractions;

public interface ITicketRepository
{
public IQueryable<Ticket> GetAllTicketsByTicketType(TicketType ticketType);
public Task<Result<Ticket>> GetTicketWithDetailsByIdAndEmailAsync(Guid id, string email);
public IQueryable<Ticket> GetTicketsByEventId(Guid eventId);
}
10 changes: 6 additions & 4 deletions TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.TicketTypes.Models;

namespace TickAPI.Tickets.Abstractions;

public interface ITicketService
{
Result<uint> GetNumberOfAvailableTicketsByType(TicketType ticketType);
Task<Result<PaginatedData<GetTicketForResellResponseDto>>> GetTicketsForResellAsync(Guid eventId, int page, int pageSize);
{
public Result<uint> GetNumberOfAvailableTicketsByType(TicketType ticketType);
public Task<Result<GetTicketDetailsResponseDto>> GetTicketDetailsAsync(Guid ticketGuid, string email);
public Task<Result<PaginatedData<GetTicketForResellResponseDto>>> GetTicketsForResellAsync(Guid eventId, int page,
int pageSize);
}
30 changes: 26 additions & 4 deletions TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,42 @@
using Microsoft.AspNetCore.Mvc;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Auth.Attributes;
using TickAPI.Common.Auth.Enums;
using TickAPI.Common.Claims.Abstractions;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.Common.Pagination.Responses;

namespace TickAPI.Tickets.Controllers;

[ApiController]
[Route("api/[controller]")]
public class TicketsController : ControllerBase
{
private readonly ITicketService _ticketService;

public TicketsController(ITicketService ticketService)
private readonly IClaimsService _claimsService;
private readonly ITicketService _ticketService;
public TicketsController(IClaimsService claimsService, ITicketService ticketService)
{
_claimsService = claimsService;
_ticketService = ticketService;
}

[AuthorizeWithPolicy(AuthPolicies.CustomerPolicy)]
[HttpGet("{id:guid}")]
public async Task<ActionResult<GetTicketDetailsResponseDto>> GetTicketDetails(Guid id)
{
var emailResult = _claimsService.GetEmailFromClaims(User.Claims);
if (emailResult.IsError)
{
return StatusCode(emailResult.StatusCode, emailResult.ErrorMsg);
}
var email = emailResult.Value!;
var ticket = await _ticketService.GetTicketDetailsAsync(id, email);
if (ticket.IsError)
{
return StatusCode(ticket.StatusCode, ticket.ErrorMsg);
}
return Ok(ticket.Value);
}

[HttpGet("/for-resell")]
public async Task<ActionResult<PaginatedData<GetTicketForResellResponseDto>>> GetTicketsForResell([FromQuery] Guid eventId, [FromQuery] int pageSize, [FromQuery] int page)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace TickAPI.Tickets.DTOs.Response;

public record GetTicketDetailsAddressDto(
string Country,
string City,
string PostalCode,
string? Street,
uint? HouseNumber,
uint? FlatNumber
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using TickAPI.Addresses.Models;

namespace TickAPI.Tickets.DTOs.Response;

public record GetTicketDetailsResponseDto
(
string NameOnTicket,
string? Seats,
decimal Price,
string Currency,
string EventName,
string OrganizerName,
DateTime StartDate,
DateTime EndDate,
GetTicketDetailsAddressDto Address,
Guid eventId
);
13 changes: 13 additions & 0 deletions TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using TickAPI.Common.Results.Generic;
using TickAPI.Common.TickApiDbContext;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.Models;
Expand Down Expand Up @@ -27,4 +28,16 @@ public IQueryable<Ticket> GetTicketsByEventId(Guid eventId)
.Include(t => t.Type.Event)
.Where(t => t.Type.Event.Id == eventId);
}

public async Task<Result<Ticket>> GetTicketWithDetailsByIdAndEmailAsync(Guid id, string email)
{
var ticket = await _tickApiDbContext.Tickets.Include(t => t.Type).Include(t => t.Type.Event)
.Include(t => t.Type.Event.Organizer).Include(t => t.Type.Event.Address)
.Where(t => (t.Id == id && t.Owner.Email == email)).FirstOrDefaultAsync();
if (ticket == null)
{
return Result<Ticket>.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
}
return Result<Ticket>.Success(ticket);
}
}
27 changes: 27 additions & 0 deletions TickAPI/TickAPI/Tickets/Services/TicketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,31 @@ public async Task<Result<PaginatedData<GetTicketForResellResponseDto>>> GetTicke
t => new GetTicketForResellResponseDto(t.Id, t.Type.Price, t.Type.Currency, t.Type.Description, t.Seats));
return Result<PaginatedData<GetTicketForResellResponseDto>>.Success(paginatedResult);
}

public async Task<Result<GetTicketDetailsResponseDto>> GetTicketDetailsAsync(Guid ticketGuid, string email)
{
var ticketRes = await _ticketRepository.GetTicketWithDetailsByIdAndEmailAsync(ticketGuid, email);
if (ticketRes.IsError)
{
return Result<GetTicketDetailsResponseDto>.PropagateError(ticketRes);
}
var ticket = ticketRes.Value!;
var ev = ticket.Type.Event;
var address = new GetTicketDetailsAddressDto(ev.Address.Country, ev.Address.City, ev.Address.PostalCode,
ev.Address.Street, ev.Address.HouseNumber, ev.Address.FlatNumber);
var ticketDetails = new GetTicketDetailsResponseDto
(
ticket.NameOnTicket,
ticket.Seats,
ticket.Type.Price,
ticket.Type.Currency,
ticket.Type.Event.Name,
ticket.Type.Event.Organizer.DisplayName,
ticket.Type.Event.StartDate,
ticket.Type.Event.EndDate,
address,
ticket.Type.Event.Id
);
return Result<GetTicketDetailsResponseDto>.Success(ticketDetails);
}
}
Loading