From 4758983a862993d5546ded20d0d12352a6da04a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Fri, 9 May 2025 15:24:01 +0200
Subject: [PATCH 1/8] Add qr service and scannin endpoint
---
.../Common/QR/Services/QRCodeService.cs | 22 +++++++++++++++++++
TickAPI/TickAPI/TickAPI.csproj | 2 ++
.../Tickets/Abstractions/ITicketRepository.cs | 1 +
.../Tickets/Abstractions/ITicketService.cs | 1 +
.../Tickets/Controllers/TicketsController.cs | 11 ++++++++++
TickAPI/TickAPI/Tickets/Models/Ticket.cs | 1 +
.../Tickets/Repositories/TicketRepository.cs | 15 +++++++++++++
.../TickAPI/Tickets/Services/TicketService.cs | 11 ++++++++++
8 files changed, 64 insertions(+)
create mode 100644 TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
diff --git a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
new file mode 100644
index 0000000..2ead564
--- /dev/null
+++ b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
@@ -0,0 +1,22 @@
+using Microsoft.AspNetCore.Components.RenderTree;
+using QRCoder;
+using System;
+using System.Collections.Generic;
+using System.Drawing.Imaging;
+using System.IO;
+using Microsoft.AspNetCore.Mvc;
+using QRCoder;
+
+namespace TickAPI.Common.QR.Services;
+
+public class QRCodeService
+{
+ public byte[] GenerateQrCode(Guid ticketId)
+ {
+ var qrGenerator = new QRCodeGenerator();
+ var qrData = qrGenerator.CreateQrCode(ticketId.ToString(), QRCodeGenerator.ECCLevel.Q);
+ var qrCode = new PngByteQRCode(qrData);
+ var qrCodeImage = qrCode.GetGraphic(20);
+ return qrCodeImage;
+ }
+}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/TickAPI.csproj b/TickAPI/TickAPI/TickAPI.csproj
index a4ca3a8..fb79365 100644
--- a/TickAPI/TickAPI/TickAPI.csproj
+++ b/TickAPI/TickAPI/TickAPI.csproj
@@ -18,6 +18,8 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
index a09c57d..8b27c3c 100644
--- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
@@ -10,4 +10,5 @@ public interface ITicketRepository
public Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id, string email);
public IQueryable GetTicketsByEventId(Guid eventId);
public IQueryable GetTicketsByCustomerEmail(string email);
+ public Task> MarkTicketAsUsed(Guid id);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
index 37b6384..6f2c924 100644
--- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
@@ -13,4 +13,5 @@ public Task>> GetTicketsForR
int pageSize);
public Task>> GetTicketsForCustomerAsync(string email, int page,
int pageSize);
+ public Task> ScanTicket(Guid ticketGuid);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
index 78979fb..eec9221 100644
--- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
+++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
@@ -65,4 +65,15 @@ public async Task>> GetTicke
}
return Ok(tickets.Value);
}
+
+ [HttpPost("/scan/{id:guid}")]
+ public async Task> ScanTicket(Guid id)
+ {
+ var res = await _ticketService.ScanTicket(id);
+ if (res.IsError)
+ {
+ return StatusCode(res.StatusCode, res.ErrorMsg);
+ }
+ return Ok(res.Value);
+ }
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Models/Ticket.cs b/TickAPI/TickAPI/Tickets/Models/Ticket.cs
index 21f765f..5106f9f 100644
--- a/TickAPI/TickAPI/Tickets/Models/Ticket.cs
+++ b/TickAPI/TickAPI/Tickets/Models/Ticket.cs
@@ -11,4 +11,5 @@ public class Ticket
public string NameOnTicket { get; set; }
public string? Seats { get; set; }
public bool ForResell { get; set; }
+ public bool Used {get; set;}
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
index 2ec02c2..c2cb18c 100644
--- a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
@@ -49,4 +49,19 @@ public async Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id,
}
return Result.Success(ticket);
}
+
+ public async Task> MarkTicketAsUsed(Guid id)
+ {
+ var ticket = await _tickApiDbContext.Tickets.FirstOrDefaultAsync(t => t.Id == id);
+
+ if (ticket != null)
+ {
+ ticket.Used = true;
+ await _tickApiDbContext.SaveChangesAsync(); // 🔄 This actually writes changes to the DB
+ return Result.Success(true);
+ }
+
+ return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
+
+ }
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
index d003a6e..abf3ec1 100644
--- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
@@ -89,4 +89,15 @@ public async Task> GetTicketDetailsAsync(Gui
);
return Result.Success(ticketDetails);
}
+
+ public async Task> ScanTicket(Guid ticketGuid)
+ {
+ var res = await _ticketRepository.MarkTicketAsUsed(ticketGuid);
+ if (res.IsError)
+ {
+ return Result.PropagateError(res);
+ }
+
+ return res;
+ }
}
\ No newline at end of file
From 943de02b0965e66dade8842174864fcdc6aac7d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Fri, 9 May 2025 15:37:06 +0200
Subject: [PATCH 2/8] Add url encoding instead of guid and add qrcode to
ticketdetails
---
.../Common/QR/Abstractions/IQRCodeService.cs | 6 ++++++
.../TickAPI/Common/QR/Services/QRCodeService.cs | 15 +++++----------
TickAPI/TickAPI/Program.cs | 3 +++
.../DTOs/Response/GetTicketDetailsResponseDto.cs | 3 ++-
TickAPI/TickAPI/Tickets/Services/TicketService.cs | 12 +++++++++---
5 files changed, 25 insertions(+), 14 deletions(-)
create mode 100644 TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
diff --git a/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs b/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
new file mode 100644
index 0000000..5e04e95
--- /dev/null
+++ b/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
@@ -0,0 +1,6 @@
+namespace TickAPI.Common.QR.Abstractions;
+
+public interface IQRCodeService
+{
+ public byte[] GenerateQrCode(Guid ticketId);
+}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
index 2ead564..f763cdf 100644
--- a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
+++ b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
@@ -1,20 +1,15 @@
-using Microsoft.AspNetCore.Components.RenderTree;
-using QRCoder;
-using System;
-using System.Collections.Generic;
-using System.Drawing.Imaging;
-using System.IO;
-using Microsoft.AspNetCore.Mvc;
-using QRCoder;
+using QRCoder;
+using TickAPI.Common.QR.Abstractions;
namespace TickAPI.Common.QR.Services;
-public class QRCodeService
+public class QRCodeService : IQRCodeService
{
public byte[] GenerateQrCode(Guid ticketId)
{
var qrGenerator = new QRCodeGenerator();
- var qrData = qrGenerator.CreateQrCode(ticketId.ToString(), QRCodeGenerator.ECCLevel.Q);
+ var url = "localhost:5124/scan/" + ticketId;
+ var qrData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
var qrCode = new PngByteQRCode(qrData);
var qrCodeImage = qrCode.GetGraphic(20);
return qrCodeImage;
diff --git a/TickAPI/TickAPI/Program.cs b/TickAPI/TickAPI/Program.cs
index 0a431a1..8a0ac0e 100644
--- a/TickAPI/TickAPI/Program.cs
+++ b/TickAPI/TickAPI/Program.cs
@@ -42,6 +42,8 @@
using TickAPI.Common.Payment.Abstractions;
using TickAPI.Common.Payment.Health;
using TickAPI.Common.Payment.Services;
+using TickAPI.Common.QR.Abstractions;
+using TickAPI.Common.QR.Services;
// Builder constants
const string allowClientPolicyName = "AllowClient";
@@ -126,6 +128,7 @@
builder.Services.AddScoped();
builder.Services.AddScoped();
builder.Services.AddScoped();
+builder.Services.AddScoped();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
diff --git a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketDetailsResponseDto.cs b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketDetailsResponseDto.cs
index 46032d5..17f4fc5 100644
--- a/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketDetailsResponseDto.cs
+++ b/TickAPI/TickAPI/Tickets/DTOs/Response/GetTicketDetailsResponseDto.cs
@@ -13,5 +13,6 @@ public record GetTicketDetailsResponseDto
DateTime StartDate,
DateTime EndDate,
GetTicketDetailsAddressDto Address,
- Guid eventId
+ Guid eventId,
+ string qrcode
);
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
index abf3ec1..5a59451 100644
--- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
@@ -1,5 +1,6 @@
using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
+using TickAPI.Common.QR.Abstractions;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;
@@ -11,11 +12,12 @@ public class TicketService : ITicketService
{
private readonly ITicketRepository _ticketRepository;
private readonly IPaginationService _paginationService;
-
- public TicketService(ITicketRepository ticketRepository, IPaginationService paginationService)
+ private readonly IQRCodeService _qrCodeService;
+ public TicketService(ITicketRepository ticketRepository, IPaginationService paginationService, IQRCodeService qrCodeService)
{
_ticketRepository = ticketRepository;
_paginationService = paginationService;
+ _qrCodeService = qrCodeService;
}
// TODO: Update this method to also count tickets cached in Redis as unavailable
@@ -74,6 +76,9 @@ public async Task> GetTicketDetailsAsync(Gui
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 qrbytes = _qrCodeService.GenerateQrCode(ticketGuid);
+ var qrcode = Convert.ToBase64String(qrbytes);
var ticketDetails = new GetTicketDetailsResponseDto
(
ticket.NameOnTicket,
@@ -85,7 +90,8 @@ public async Task> GetTicketDetailsAsync(Gui
ticket.Type.Event.StartDate,
ticket.Type.Event.EndDate,
address,
- ticket.Type.Event.Id
+ ticket.Type.Event.Id,
+ qrcode
);
return Result.Success(ticketDetails);
}
From 12d579cd1e5875ff1d4fa1e6a301dd844cd22846 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sat, 10 May 2025 17:13:20 +0200
Subject: [PATCH 3/8] Add retrieving urls
---
.../TickAPI/Common/QR/Abstractions/IQRCodeService.cs | 2 +-
TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs | 3 +--
.../TickAPI/Tickets/Abstractions/ITicketService.cs | 4 +++-
.../TickAPI/Tickets/Controllers/TicketsController.cs | 10 ++++++----
TickAPI/TickAPI/Tickets/Services/TicketService.cs | 11 +++++++----
5 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs b/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
index 5e04e95..94b2690 100644
--- a/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
+++ b/TickAPI/TickAPI/Common/QR/Abstractions/IQRCodeService.cs
@@ -2,5 +2,5 @@
public interface IQRCodeService
{
- public byte[] GenerateQrCode(Guid ticketId);
+ public byte[] GenerateQrCode(string url);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
index f763cdf..1986f90 100644
--- a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
+++ b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
@@ -5,10 +5,9 @@ namespace TickAPI.Common.QR.Services;
public class QRCodeService : IQRCodeService
{
- public byte[] GenerateQrCode(Guid ticketId)
+ public byte[] GenerateQrCode(string url)
{
var qrGenerator = new QRCodeGenerator();
- var url = "localhost:5124/scan/" + ticketId;
var qrData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
var qrCode = new PngByteQRCode(qrData);
var qrCodeImage = qrCode.GetGraphic(20);
diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
index 76b1b06..abca918 100644
--- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
@@ -9,10 +9,12 @@ namespace TickAPI.Tickets.Abstractions;
public interface ITicketService
{
public Result GetNumberOfAvailableTicketsByType(TicketType ticketType);
- public Task> GetTicketDetailsAsync(Guid ticketGuid, string email);
public Task>> GetTicketsForResellAsync(Guid eventId, int page,
int pageSize);
public Task>> GetTicketsForCustomerAsync(string email, int page,
int pageSize, TicketFiltersDto ? ticketFilters = null);
public Task> ScanTicket(Guid ticketGuid);
+
+ public Task> GetTicketDetailsAsync(Guid ticketGuid, string email,
+ string scanUrl);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
index 969a974..2473b96 100644
--- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
+++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
@@ -31,11 +31,12 @@ public async Task> GetTicketDetails(Gu
return emailResult.ToObjectResult();
}
var email = emailResult.Value!;
- var ticket = await _ticketService.GetTicketDetailsAsync(id, email);
+ string? scanTicketUrl = Url.Action("ScanTicket", "Tickets", new { id = id }, Request.Scheme);
+ var ticket = await _ticketService.GetTicketDetailsAsync(id, email, scanTicketUrl);
return ticket.ToObjectResult();
}
- [HttpGet("/for-resell")]
+ [HttpGet("for-resell")]
public async Task>> GetTicketsForResell([FromQuery] Guid eventId, [FromQuery] int pageSize, [FromQuery] int page)
{
var result = await _ticketService.GetTicketsForResellAsync(eventId, page, pageSize);
@@ -55,8 +56,8 @@ public async Task>> GetTicke
return tickets.ToObjectResult();
}
- [HttpPost("/scan/{id:guid}")]
- public async Task> ScanTicket(Guid id)
+ [HttpGet("scan/{id:guid}")]
+ public async Task> ScanTicket([FromQuery] Guid id)
{
var res = await _ticketService.ScanTicket(id);
if (res.IsError)
@@ -65,4 +66,5 @@ public async Task> ScanTicket(Guid id)
}
return Ok(res.Value);
}
+
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
index e6987c8..0da33d2 100644
--- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
@@ -1,4 +1,5 @@
-using TickAPI.Common.Pagination.Abstractions;
+using Azure.Core;
+using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.QR.Abstractions;
using TickAPI.Common.Results.Generic;
@@ -72,7 +73,7 @@ public async Task>> GetTicketsForC
return Result>.Success(paginatedResult);
}
- public async Task> GetTicketDetailsAsync(Guid ticketGuid, string email)
+ public async Task> GetTicketDetailsAsync(Guid ticketGuid, string email, string scanUrl)
{
var ticketRes = await _ticketRepository.GetTicketWithDetailsByIdAndEmailAsync(ticketGuid, email);
if (ticketRes.IsError)
@@ -83,8 +84,8 @@ public async Task> GetTicketDetailsAsync(Gui
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 qrbytes = _qrCodeService.GenerateQrCode(ticketGuid);
+
+ var qrbytes = _qrCodeService.GenerateQrCode(scanUrl);
var qrcode = Convert.ToBase64String(qrbytes);
var ticketDetails = new GetTicketDetailsResponseDto
(
@@ -113,4 +114,6 @@ public async Task> ScanTicket(Guid ticketGuid)
return res;
}
+
+
}
\ No newline at end of file
From 1cda709ccaa38fcfcc0de7d62f3e06d2a53a2b6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sat, 10 May 2025 17:21:14 +0200
Subject: [PATCH 4/8] Handle scanning used tickets
---
.../Tickets/Controllers/TicketsController.cs | 3 ++-
.../Tickets/Repositories/TicketRepository.cs | 13 +++++--------
2 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
index 2473b96..f9f5512 100644
--- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
+++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
@@ -5,6 +5,7 @@
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.Common.Pagination.Responses;
+using TickAPI.Common.Results;
using TickAPI.Tickets.DTOs.Request;
namespace TickAPI.Tickets.Controllers;
@@ -32,7 +33,7 @@ public async Task> GetTicketDetails(Gu
}
var email = emailResult.Value!;
string? scanTicketUrl = Url.Action("ScanTicket", "Tickets", new { id = id }, Request.Scheme);
- var ticket = await _ticketService.GetTicketDetailsAsync(id, email, scanTicketUrl);
+ var ticket = await _ticketService.GetTicketDetailsAsync(id, email, scanTicketUrl!);
return ticket.ToObjectResult();
}
diff --git a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
index c2cb18c..1180158 100644
--- a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
@@ -53,15 +53,12 @@ public async Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id,
public async Task> MarkTicketAsUsed(Guid id)
{
var ticket = await _tickApiDbContext.Tickets.FirstOrDefaultAsync(t => t.Id == id);
-
- if (ticket != null)
+ if (ticket == null || ticket.Used)
{
- ticket.Used = true;
- await _tickApiDbContext.SaveChangesAsync(); // 🔄 This actually writes changes to the DB
- return Result.Success(true);
+ return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
}
-
- return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
-
+ ticket.Used = true;
+ await _tickApiDbContext.SaveChangesAsync();
+ return Result.Success(true);
}
}
\ No newline at end of file
From 102ff0689ec8685ae71de3661a65a3ff1a9065eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sat, 10 May 2025 17:39:23 +0200
Subject: [PATCH 5/8] Add test
---
.../Tickets/Services/TicketServiceTests.cs | 64 +++++++++++++++----
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
index 389f7a4..8b46ba2 100644
--- a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
+++ b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
@@ -4,6 +4,8 @@
using TickAPI.Addresses.Models;
using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
+using TickAPI.Common.QR.Abstractions;
+using TickAPI.Common.Results;
using TickAPI.Common.Results.Generic;
using TickAPI.Customers.Models;
using TickAPI.Events.Models;
@@ -27,12 +29,13 @@ public void GetNumberOfAvailableTicketsByType_AmountsAreCorrect_ShouldReturnCorr
var ticketRepositoryMock = new Mock();
var paginationServiceMock = new Mock();
+ var qrServiceMock = new Mock();
ticketRepositoryMock
.Setup(m => m.GetAllTicketsByTicketType(type))
.Returns(ticketList.AsQueryable());
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = sut.GetNumberOfAvailableTicketsByType(type);
@@ -51,12 +54,13 @@ public void GetNumberOfAvailableTicketsByType_WhenMoreTicketExistThanMaxCount_Sh
var ticketRepositoryMock = new Mock();
var paginationServiceMock = new Mock();
+ var qrServiceMock = new Mock();
ticketRepositoryMock
.Setup(m => m.GetAllTicketsByTicketType(type))
.Returns(ticketList.AsQueryable());
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = sut.GetNumberOfAvailableTicketsByType(type);
@@ -150,7 +154,9 @@ public async Task GetTicketsForResellAsync_WhenDataIsValid_ShouldReturnSuccess()
It.IsAny>()))
.Returns(mappedData);
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var qrServiceMock = new Mock();
+
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);
@@ -226,8 +232,9 @@ public async Task GetTicketsForResellAsync_WhenNoTicketsForResell_ShouldReturnEm
paginatedData,
It.IsAny>()))
.Returns(mappedData);
+ var qrServiceMock = new Mock();
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);
@@ -270,7 +277,9 @@ public async Task GetTicketsForResellAsync_WhenPaginationFails_ShouldPropagateEr
paginationServiceMock.Setup(p => p.PaginateAsync(It.IsAny>(), pageSize, page))
.ReturnsAsync(Result>.Failure(statusCode, errorMsg));
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var qrServiceMock = new Mock();
+
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);
@@ -321,8 +330,9 @@ public async Task GetTicketsForResellAsync_WhenNoTicketsForEvent_ShouldReturnEmp
paginatedData,
It.IsAny>()))
.Returns(mappedData);
+ var qrServiceMock = new Mock();
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);
@@ -371,7 +381,7 @@ public async Task GetTicketDetailsAsync_WhenTicketExistsForTheUser_ShouldReturnT
},
};
string email = "123@123.com";
-
+ string scanurl = "http://localhost";
Mock ticketRepositoryMock = new Mock();
var paginationServiceMock = new Mock();
@@ -379,11 +389,14 @@ public async Task GetTicketDetailsAsync_WhenTicketExistsForTheUser_ShouldReturnT
ticketRepositoryMock.Setup(m => m.GetTicketWithDetailsByIdAndEmailAsync(ticket.Id, email))
.ReturnsAsync(Result.Success(ticket));
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var qrServiceMock = new Mock();
+ qrServiceMock.Setup(m => m.GenerateQrCode(scanurl)).Returns([]);
+
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
- var res = await sut.GetTicketDetailsAsync(ticket.Id, email);
+ var res = await sut.GetTicketDetailsAsync(ticket.Id, email, scanurl);
// Assert
@@ -415,18 +428,20 @@ public async Task GetTicketDetailsAsync_WhenTicketDoesNotExistForTheUser_ShouldR
Guid ticketId = Guid.NewGuid();
string email = "123@123.com";
+ string scanUrl = "http://localhost";
Mock ticketRepositoryMock = new Mock();
ticketRepositoryMock.Setup(m => m.GetTicketWithDetailsByIdAndEmailAsync(ticketId, email)).
ReturnsAsync(Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist " +
"for this user"));
var paginationServiceMock = new Mock();
+ var qrServiceMock = new Mock();
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
- var res = await sut.GetTicketDetailsAsync(ticketId, email);
+ var res = await sut.GetTicketDetailsAsync(ticketId, email, scanUrl);
// Assert
@@ -505,7 +520,10 @@ public async Task GetTicketsForCustomerAsync_WithValidInput_ReturnsSuccessResult
paginationServiceMock.Setup(p => p.MapData(paginatedData, It.IsAny>()))
.Returns(mappedPaginatedData);
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+
+ var qrServiceMock = new Mock();
+
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForCustomerAsync(email, page, pageSize);
@@ -543,7 +561,9 @@ public async Task GetTicketsForCustomerAsync_WhenUserHasNoTickets_ReturnsEmptyPa
paginationServiceMock.Setup(p => p.MapData(emptyPaginatedData, It.IsAny>()))
.Returns(mappedEmptyPaginatedData);
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);
+ var qrServiceMock = new Mock();
+
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var result = await sut.GetTicketsForCustomerAsync(email, page, pageSize);
@@ -552,4 +572,22 @@ public async Task GetTicketsForCustomerAsync_WhenUserHasNoTickets_ReturnsEmptyPa
Assert.True(result.IsSuccess);
Assert.Empty(result.Value!.Data);
}
+
+ [Fact]
+ public async Task ScanTicket_WhenScanningSuccesful_ShouldReturnSuccess()
+ {
+ // Arrange
+ var guid = Guid.NewGuid();
+ var ticketRepositoryMock = new Mock();
+ ticketRepositoryMock.Setup(m => m.MarkTicketAsUsed(guid)).ReturnsAsync(Result.Success(true));
+ var paginationServiceMock = new Mock();
+ var qrServiceMock = new Mock();
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
+
+ // Act
+ var res = await sut.ScanTicket(guid);
+
+ // Assert
+ Assert.True(res.IsSuccess);
+ }
}
\ No newline at end of file
From 5f6caeeb7ec11f512d2a4983d4c875b015d60127 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sat, 10 May 2025 17:42:02 +0200
Subject: [PATCH 6/8] new spacing
---
TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs | 2 +-
TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
index 8b46ba2..5a56bc2 100644
--- a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
+++ b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
@@ -582,7 +582,7 @@ public async Task ScanTicket_WhenScanningSuccesful_ShouldReturnSuccess()
ticketRepositoryMock.Setup(m => m.MarkTicketAsUsed(guid)).ReturnsAsync(Result.Success(true));
var paginationServiceMock = new Mock();
var qrServiceMock = new Mock();
- var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
+ var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
// Act
var res = await sut.ScanTicket(guid);
diff --git a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
index 1986f90..9d5f5c1 100644
--- a/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
+++ b/TickAPI/TickAPI/Common/QR/Services/QRCodeService.cs
@@ -10,7 +10,7 @@ public byte[] GenerateQrCode(string url)
var qrGenerator = new QRCodeGenerator();
var qrData = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.Q);
var qrCode = new PngByteQRCode(qrData);
- var qrCodeImage = qrCode.GetGraphic(20);
+ var qrCodeImage = qrCode.GetGraphic(20);
return qrCodeImage;
}
}
\ No newline at end of file
From c6a9a3f69dd1f7c880d5b32f00cbbc7b909afa33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sun, 11 May 2025 12:30:01 +0200
Subject: [PATCH 7/8] Trzcinskik comments
---
.../Tickets/Services/TicketServiceTests.cs | 2 +-
.../TickAPI/Tickets/Abstractions/ITicketRepository.cs | 5 +++--
.../TickAPI/Tickets/Abstractions/ITicketService.cs | 4 ++--
.../TickAPI/Tickets/Controllers/TicketsController.cs | 8 ++------
.../TickAPI/Tickets/Repositories/TicketRepository.cs | 11 ++++++++---
TickAPI/TickAPI/Tickets/Services/TicketService.cs | 8 ++------
6 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
index 5a56bc2..331853f 100644
--- a/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
+++ b/TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
@@ -579,7 +579,7 @@ public async Task ScanTicket_WhenScanningSuccesful_ShouldReturnSuccess()
// Arrange
var guid = Guid.NewGuid();
var ticketRepositoryMock = new Mock();
- ticketRepositoryMock.Setup(m => m.MarkTicketAsUsed(guid)).ReturnsAsync(Result.Success(true));
+ ticketRepositoryMock.Setup(m => m.MarkTicketAsUsed(guid)).ReturnsAsync(Result.Success());
var paginationServiceMock = new Mock();
var qrServiceMock = new Mock();
var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object, qrServiceMock.Object);
diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
index 8b27c3c..6290950 100644
--- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
@@ -1,4 +1,5 @@
-using TickAPI.Common.Results.Generic;
+using TickAPI.Common.Results;
+using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.Models;
using TickAPI.TicketTypes.Models;
@@ -10,5 +11,5 @@ public interface ITicketRepository
public Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id, string email);
public IQueryable GetTicketsByEventId(Guid eventId);
public IQueryable GetTicketsByCustomerEmail(string email);
- public Task> MarkTicketAsUsed(Guid id);
+ public Task MarkTicketAsUsed(Guid id);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
index abca918..c722a8c 100644
--- a/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
@@ -1,4 +1,5 @@
using TickAPI.Common.Pagination.Responses;
+using TickAPI.Common.Results;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.DTOs.Request;
using TickAPI.Tickets.DTOs.Response;
@@ -13,8 +14,7 @@ public Task>> GetTicketsForR
int pageSize);
public Task>> GetTicketsForCustomerAsync(string email, int page,
int pageSize, TicketFiltersDto ? ticketFilters = null);
- public Task> ScanTicket(Guid ticketGuid);
-
+ public Task ScanTicket(Guid ticketGuid);
public Task> GetTicketDetailsAsync(Guid ticketGuid, string email,
string scanUrl);
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
index f9f5512..77b45e2 100644
--- a/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
+++ b/TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
@@ -58,14 +58,10 @@ public async Task>> GetTicke
}
[HttpGet("scan/{id:guid}")]
- public async Task> ScanTicket([FromQuery] Guid id)
+ public async Task> ScanTicket(Guid id)
{
var res = await _ticketService.ScanTicket(id);
- if (res.IsError)
- {
- return StatusCode(res.StatusCode, res.ErrorMsg);
- }
- return Ok(res.Value);
+ return res.ToObjectResult();
}
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
index 1180158..fe4c5f1 100644
--- a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
+using TickAPI.Common.Results;
using TickAPI.Common.Results.Generic;
using TickAPI.Common.TickApiDbContext;
using TickAPI.Tickets.Abstractions;
@@ -50,15 +51,19 @@ public async Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id,
return Result.Success(ticket);
}
- public async Task> MarkTicketAsUsed(Guid id)
+ public async Task MarkTicketAsUsed(Guid id)
{
var ticket = await _tickApiDbContext.Tickets.FirstOrDefaultAsync(t => t.Id == id);
if (ticket == null || ticket.Used)
{
- return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
+ return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
+ }
+ if (ticket.Used)
+ {
+ return Result.Failure(StatusCodes.Status400BadRequest, "Ticket already used");
}
ticket.Used = true;
await _tickApiDbContext.SaveChangesAsync();
- return Result.Success(true);
+ return Result.Success();
}
}
\ No newline at end of file
diff --git a/TickAPI/TickAPI/Tickets/Services/TicketService.cs b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
index 0da33d2..27b60fd 100644
--- a/TickAPI/TickAPI/Tickets/Services/TicketService.cs
+++ b/TickAPI/TickAPI/Tickets/Services/TicketService.cs
@@ -2,6 +2,7 @@
using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.QR.Abstractions;
+using TickAPI.Common.Results;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Request;
@@ -104,14 +105,9 @@ public async Task> GetTicketDetailsAsync(Gui
return Result.Success(ticketDetails);
}
- public async Task> ScanTicket(Guid ticketGuid)
+ public async Task ScanTicket(Guid ticketGuid)
{
var res = await _ticketRepository.MarkTicketAsUsed(ticketGuid);
- if (res.IsError)
- {
- return Result.PropagateError(res);
- }
-
return res;
}
From af70c9e9e8d18afdeb39950534b7014a48e7d613 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stanis=C5=82aw?=
<62651497+staszkiet@users.noreply.github.com>
Date: Sun, 11 May 2025 13:45:41 +0200
Subject: [PATCH 8/8] if chang
---
TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
index fe4c5f1..e5abb5e 100644
--- a/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
+++ b/TickAPI/TickAPI/Tickets/Repositories/TicketRepository.cs
@@ -54,7 +54,7 @@ public async Task> GetTicketWithDetailsByIdAndEmailAsync(Guid id,
public async Task MarkTicketAsUsed(Guid id)
{
var ticket = await _tickApiDbContext.Tickets.FirstOrDefaultAsync(t => t.Id == id);
- if (ticket == null || ticket.Used)
+ if (ticket == null)
{
return Result.Failure(StatusCodes.Status404NotFound, "Ticket with this id doesn't exist");
}