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
12 changes: 6 additions & 6 deletions TickAPI/TickAPI.Tests/Events/Services/EventServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ public async Task GetOrganizerEvents_WhenPaginationSucceeds_ShouldReturnPaginate
);

var organizerEvents = organizer.Events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEventsByOranizer(organizer)).Returns(organizerEvents);
eventRepositoryMock.Setup(p => p.GetEventsByOranizerAsync(organizer)).ReturnsAsync(organizerEvents);

paginationServiceMock
.Setup(p => p.PaginateAsync(organizerEvents, pageSize, page))
Expand Down Expand Up @@ -425,7 +425,7 @@ public async Task GetOrganizerEvents_WhenPaginationFails_ShouldPropagateError()
var ticketServiceMock = new Mock<ITicketService>();

var organizerEvents = organizer.Events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEventsByOranizer(organizer)).Returns(organizerEvents);
eventRepositoryMock.Setup(p => p.GetEventsByOranizerAsync(organizer)).ReturnsAsync(organizerEvents);

paginationServiceMock
.Setup(p => p.PaginateAsync(organizerEvents, pageSize, page))
Expand Down Expand Up @@ -477,7 +477,7 @@ public async Task GetEventsAsync_WhenPaginationSucceeds_ShouldReturnPaginatedEve
);

var eventsQueryable = events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable);
eventRepositoryMock.Setup(p => p.GetEventsAsync()).ReturnsAsync(eventsQueryable);

paginationServiceMock
.Setup(p => p.PaginateAsync(eventsQueryable, pageSize, page))
Expand Down Expand Up @@ -541,7 +541,7 @@ public async Task GetEventsAsync_WhenPaginationFails_ShouldPropagateError()
var ticketServiceMock = new Mock<ITicketService>();

var eventsQueryable = events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable);
eventRepositoryMock.Setup(p => p.GetEventsAsync()).ReturnsAsync(eventsQueryable);

paginationServiceMock
.Setup(p => p.PaginateAsync(eventsQueryable, pageSize, page))
Expand Down Expand Up @@ -583,7 +583,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenSuccessful_ShouldReturnPag
var ticketServiceMock = new Mock<ITicketService>();

var eventsQueryable = events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable);
eventRepositoryMock.Setup(p => p.GetEventsAsync()).ReturnsAsync(eventsQueryable);

var paginationDetails = new PaginationDetails(1, 3);
paginationServiceMock
Expand Down Expand Up @@ -625,7 +625,7 @@ public async Task GetEventsPaginationDetailsAsync_WhenFails_ShouldReturnError()
var ticketServiceMock = new Mock<ITicketService>();

var eventsQueryable = events.AsQueryable();
eventRepositoryMock.Setup(p => p.GetEvents()).Returns(eventsQueryable);
eventRepositoryMock.Setup(p => p.GetEventsAsync()).ReturnsAsync(eventsQueryable);

paginationServiceMock
.Setup(p => p.GetPaginationDetailsAsync(eventsQueryable, pageSize))
Expand Down
4 changes: 2 additions & 2 deletions TickAPI/TickAPI/Events/Abstractions/IEventRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace TickAPI.Events.Abstractions;
public interface IEventRepository
{
public Task AddNewEventAsync(Event @event);
public IQueryable<Event> GetEvents();
public IQueryable<Event> GetEventsByOranizer(Organizer organizer);
public Task<IQueryable<Event>> GetEventsAsync();
public Task<IQueryable<Event>> GetEventsByOranizerAsync(Organizer organizer);
public Task<Result<Event>> GetEventByIdAsync(Guid eventId);
public Task<Result> SaveEventAsync(Event ev);
public Task<Result<Event>> GetEventByIdAndOrganizerAsync(Guid eventId, Organizer organizer);
Expand Down
100 changes: 100 additions & 0 deletions TickAPI/TickAPI/Events/Repositories/BaseEventRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Microsoft.EntityFrameworkCore;
using TickAPI.Common.Results;
using TickAPI.Common.Results.Generic;
using TickAPI.Common.TickApiDbContext;
using TickAPI.Events.Abstractions;
using TickAPI.Events.Models;
using TickAPI.Organizers.Models;

namespace TickAPI.Events.Repositories;

public class BaseEventRepository : IEventRepository
{
private readonly TickApiDbContext _tickApiDbContext;

public BaseEventRepository(TickApiDbContext tickApiDbContext)
{
_tickApiDbContext = tickApiDbContext;
}

public async Task AddNewEventAsync(Event @event)
{
_tickApiDbContext.Events.Add(@event);
await _tickApiDbContext.SaveChangesAsync();
}

public async Task<IQueryable<Event>> GetEventsAsync()
{
return _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories);
}

public async Task<IQueryable<Event>> GetEventsByOranizerAsync(Organizer organizer)
{
return _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories)
.Where(e => e.Organizer.Id == organizer.Id);
}

public async Task<Result<Event>> GetEventByIdAsync(Guid eventId)
{
var @event = await _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories)
.FirstOrDefaultAsync(e => e.Id == eventId);

if (@event == null)
{
return Result<Event>.Failure(StatusCodes.Status404NotFound, $"event with id {eventId} not found");
}

return Result<Event>.Success(@event);
}

public async Task<Result> SaveEventAsync(Event ev)
{
var fromDb = await GetEventByIdAsync(ev.Id);
if (fromDb.IsError)
return Result.PropagateError(fromDb);
await _tickApiDbContext.SaveChangesAsync();
return Result.Success();
}

public async Task<Result<Event>> GetEventByIdAndOrganizerAsync(Guid eventId, Organizer organizer)
{
var organizerEvents = GetEventsByOranizerAsync(organizer);
var ev = await (await organizerEvents).Where(e => e.Id == eventId).FirstAsync();
if (ev is null)
{
return Result<Event>.Failure(StatusCodes.Status404NotFound, $"Event with id {eventId} not found for organizer with id {organizer.Id}");
}
return Result<Event>.Success(ev);
}

public async Task<decimal> GetEventRevenue(Guid eventId)
{
var query = from tickets in _tickApiDbContext.Tickets
join _ticketTypes in _tickApiDbContext.TicketTypes on tickets.Type.Id equals _ticketTypes.Id
join events in _tickApiDbContext.Events on _ticketTypes.Event.Id equals events.Id
where events.Id == eventId
select new { price = _ticketTypes.Price };
var val = await query.SumAsync(x => x.price);
return val;
}

public async Task<int> GetEventSoldTicketsCount(Guid eventId)
{
var query = from tickets in _tickApiDbContext.Tickets
join _ticketTypes in _tickApiDbContext.TicketTypes on tickets.Type.Id equals _ticketTypes.Id
join events in _tickApiDbContext.Events on _ticketTypes.Event.Id equals events.Id
where events.Id == eventId
select new { id = tickets.Id };
var val = await query.CountAsync();
return val;
}
}
135 changes: 77 additions & 58 deletions TickAPI/TickAPI/Events/Repositories/EventRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,91 +10,110 @@ namespace TickAPI.Events.Repositories;

public class EventRepository : IEventRepository
{
private readonly BaseEventRepository _baseEventRepository;
private readonly TickApiDbContext _tickApiDbContext;

public EventRepository(TickApiDbContext tickApiDbContext)
public EventRepository(BaseEventRepository baseEventRepository, TickApiDbContext tickApiDbContext)
{
_baseEventRepository = baseEventRepository;
_tickApiDbContext = tickApiDbContext;
}
public async Task AddNewEventAsync(Event @event)

public Task AddNewEventAsync(Event @event)
{
_tickApiDbContext.Events.Add(@event);
await _tickApiDbContext.SaveChangesAsync();
return _baseEventRepository.AddNewEventAsync(@event);
}

public IQueryable<Event> GetEvents()
public async Task<IQueryable<Event>> GetEventsAsync()
{
return _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories);
var events = await _baseEventRepository.GetEventsAsync();
await UpdateEventsStatuses(events);
return events;
}

public IQueryable<Event> GetEventsByOranizer(Organizer organizer)
public async Task<IQueryable<Event>> GetEventsByOranizerAsync(Organizer organizer)
{
return _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories)
.Where(e => e.Organizer.Id == organizer.Id);
var events = await _baseEventRepository.GetEventsByOranizerAsync(organizer);
await UpdateEventsStatuses(events);
return events;
}

public async Task<Result<Event>> GetEventByIdAsync(Guid eventId)
{
var @event = await _tickApiDbContext.Events
.Include(e => e.Address)
.Include(e => e.TicketTypes)
.Include(e => e.Categories)
.FirstOrDefaultAsync(e => e.Id == eventId);

if (@event == null)
{
return Result<Event>.Failure(StatusCodes.Status404NotFound, $"event with id {eventId} not found");
}

return Result<Event>.Success(@event);
var evResult = await _baseEventRepository.GetEventByIdAsync(eventId);
if (evResult.IsError)
return evResult;
var ev = evResult.Value!;
await UpdateEventStatuses([ev.Id]);
return Result<Event>.Success(ev);
}

public async Task<Result> SaveEventAsync(Event ev)
public Task<Result> SaveEventAsync(Event ev)
{
var fromDb = await GetEventByIdAsync(ev.Id);
if (fromDb.IsError)
return Result.PropagateError(fromDb);
await _tickApiDbContext.SaveChangesAsync();
return Result.Success();
return _baseEventRepository.SaveEventAsync(ev);
}

public async Task<Result<Event>> GetEventByIdAndOrganizerAsync(Guid eventId, Organizer organizer)
{
var organizerEvents = GetEventsByOranizer(organizer);
var ev = await organizerEvents.Where(e => e.Id == eventId).FirstAsync();
if (ev is null)
{
return Result<Event>.Failure(StatusCodes.Status404NotFound, $"Event with id {eventId} not found for organizer with id {organizer.Id}");
}
var evResult = await _baseEventRepository.GetEventByIdAndOrganizerAsync(eventId, organizer);
if (evResult.IsError)
return evResult;
var ev = evResult.Value!;
await UpdateEventStatuses([ev.Id]);
return Result<Event>.Success(ev);
}

public async Task<decimal> GetEventRevenue(Guid eventId)
public Task<decimal> GetEventRevenue(Guid eventId)
{
return _baseEventRepository.GetEventRevenue(eventId);
}

public Task<int> GetEventSoldTicketsCount(Guid eventId)
{
var query = from tickets in _tickApiDbContext.Tickets
join _ticketTypes in _tickApiDbContext.TicketTypes on tickets.Type.Id equals _ticketTypes.Id
join events in _tickApiDbContext.Events on _ticketTypes.Event.Id equals events.Id
where events.Id == eventId
select new { price = _ticketTypes.Price };
var val = await query.SumAsync(x => x.price);
return val;
return _baseEventRepository.GetEventSoldTicketsCount(eventId);
}

public async Task<int> GetEventSoldTicketsCount(Guid eventId)

private async Task UpdateEventStatuses(List<Guid> guids)
{
var eventsQuery = _tickApiDbContext.Events
.Where(e => guids.Contains(e.Id));

await UpdateEventsStatuses(eventsQuery);
}

private async Task UpdateEventsStatuses(IQueryable<Event> eventsQuery)
{
var query = from tickets in _tickApiDbContext.Tickets
join _ticketTypes in _tickApiDbContext.TicketTypes on tickets.Type.Id equals _ticketTypes.Id
join events in _tickApiDbContext.Events on _ticketTypes.Event.Id equals events.Id
where events.Id == eventId
select new { id = tickets.Id };
var val = await query.CountAsync();
return val;
var now = DateTime.UtcNow;
var events = await eventsQuery
.Include(e => e.TicketTypes)
.ThenInclude(tt => tt.Tickets)
.ToListAsync();

foreach (var ev in events)
{
if (ev.EndDate < now)
{
ev.EventStatus = EventStatus.Finished;
}
else if (ev.StartDate <= now && ev.EndDate >= now)
{
ev.EventStatus = EventStatus.InProgress;
}
else
{
var totalTickets = ev.TicketTypes.Sum(tt => tt.MaxCount);
var soldTickets = ev.TicketTypes.Sum(tt => tt.Tickets.Count);
if (totalTickets > 0 && soldTickets >= totalTickets)
{
ev.EventStatus = EventStatus.SoldOut;
}
else
{
ev.EventStatus = EventStatus.TicketsAvailable;
}
}
}

await _tickApiDbContext.SaveChangesAsync();
}
}
}
8 changes: 4 additions & 4 deletions TickAPI/TickAPI/Events/Services/EventService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,27 +118,27 @@ public async Task<Result<Event>> CreateNewEventAsync(string name, string descri

public async Task<Result<PaginatedData<GetEventResponseDto>>> GetOrganizerEventsAsync(Organizer organizer, int page, int pageSize, EventFiltersDto? eventFilters = null)
{
var organizerEvents = _eventRepository.GetEventsByOranizer(organizer);
var organizerEvents = await _eventRepository.GetEventsByOranizerAsync(organizer);
var filteredOrganizerEvents = ApplyEventFilters(organizerEvents, eventFilters);
return await GetPaginatedEventsAsync(filteredOrganizerEvents, page, pageSize);
}

public async Task<Result<PaginationDetails>> GetOrganizerEventsPaginationDetailsAsync(Organizer organizer, int pageSize)
{
var organizerEvents = _eventRepository.GetEventsByOranizer(organizer);
var organizerEvents = await _eventRepository.GetEventsByOranizerAsync(organizer);
return await _paginationService.GetPaginationDetailsAsync(organizerEvents, pageSize);
}

public async Task<Result<PaginatedData<GetEventResponseDto>>> GetEventsAsync(int page, int pageSize, EventFiltersDto? eventFilters = null)
{
var events = _eventRepository.GetEvents();
var events = await _eventRepository.GetEventsAsync();
var filteredEvents = ApplyEventFilters(events, eventFilters);
return await GetPaginatedEventsAsync(filteredEvents, page, pageSize);
}

public async Task<Result<PaginationDetails>> GetEventsPaginationDetailsAsync(int pageSize)
{
var events = _eventRepository.GetEvents();
var events = await _eventRepository.GetEventsAsync();
return await _paginationService.GetPaginationDetailsAsync(events, pageSize);
}

Expand Down
1 change: 1 addition & 0 deletions TickAPI/TickAPI/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
})
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Authentication:Google:ClientId"];

Check warning on line 73 in TickAPI/TickAPI/Program.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference assignment.
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];

Check warning on line 74 in TickAPI/TickAPI/Program.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference assignment.
})
.AddJwtBearer(options =>
{
Expand Down Expand Up @@ -110,6 +110,7 @@
// Add event services.
builder.Services.AddScoped<IEventService, EventService>();
builder.Services.AddScoped<IEventRepository, EventRepository>();
builder.Services.AddScoped<BaseEventRepository, BaseEventRepository>();

// Add address services.
builder.Services.AddScoped<IAddressService, AddressService>();
Expand Down
Loading