242 lines
7.0 KiB
C#
242 lines
7.0 KiB
C#
|
|
using Microsoft.AspNetCore.Authorization;
|
||
|
|
using Microsoft.AspNetCore.Mvc;
|
||
|
|
using Microsoft.EntityFrameworkCore;
|
||
|
|
using RacePlannerApi.Data;
|
||
|
|
using RacePlannerApi.DTOs;
|
||
|
|
using RacePlannerApi.Models;
|
||
|
|
|
||
|
|
namespace RacePlannerApi.Controllers;
|
||
|
|
|
||
|
|
[ApiController]
|
||
|
|
[Route("api/[controller]")]
|
||
|
|
[Authorize]
|
||
|
|
public class EventsController : ControllerBase
|
||
|
|
{
|
||
|
|
private readonly RacePlannerDbContext _context;
|
||
|
|
|
||
|
|
public EventsController(RacePlannerDbContext context)
|
||
|
|
{
|
||
|
|
_context = context;
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPost]
|
||
|
|
[Authorize(Roles = "Organizer")]
|
||
|
|
public async Task<ActionResult<EventDto>> CreateEvent(CreateEventRequest request)
|
||
|
|
{
|
||
|
|
var userId = GetCurrentUserId();
|
||
|
|
if (userId == null)
|
||
|
|
{
|
||
|
|
return Unauthorized();
|
||
|
|
}
|
||
|
|
|
||
|
|
var eventEntity = new Event
|
||
|
|
{
|
||
|
|
Name = request.Name,
|
||
|
|
Description = request.Description,
|
||
|
|
EventDate = request.EventDate,
|
||
|
|
Location = request.Location,
|
||
|
|
Category = request.Category,
|
||
|
|
Tags = request.Tags ?? new List<string>(),
|
||
|
|
MaxParticipants = request.MaxParticipants,
|
||
|
|
OrganizerId = userId.Value,
|
||
|
|
Status = EventStatus.Draft
|
||
|
|
};
|
||
|
|
|
||
|
|
_context.Events.Add(eventEntity);
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
// Load organizer for response
|
||
|
|
await _context.Entry(eventEntity).Reference(e => e.Organizer).LoadAsync();
|
||
|
|
|
||
|
|
return CreatedAtAction(
|
||
|
|
nameof(GetEvent),
|
||
|
|
new { id = eventEntity.Id },
|
||
|
|
MapToEventDto(eventEntity));
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet]
|
||
|
|
[AllowAnonymous]
|
||
|
|
public async Task<ActionResult<IEnumerable<EventDto>>> GetEvents(
|
||
|
|
[FromQuery] EventFilterRequest? filter = null)
|
||
|
|
{
|
||
|
|
var query = _context.Events
|
||
|
|
.Include(e => e.Organizer)
|
||
|
|
.Include(e => e.Registrations)
|
||
|
|
.AsQueryable();
|
||
|
|
|
||
|
|
// Apply filters
|
||
|
|
if (filter?.Category != null)
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.Category == filter.Category);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filter?.Tags != null && filter.Tags.Any())
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.Tags.Any(t => filter.Tags.Contains(t)));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filter?.FromDate != null)
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.EventDate >= filter.FromDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filter?.ToDate != null)
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.EventDate <= filter.ToDate);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filter?.Status != null && Enum.TryParse<EventStatus>(filter.Status, out var status))
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.Status == status);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filter?.OrganizerId != null)
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.OrganizerId == filter.OrganizerId);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Default to showing published events only for anonymous users
|
||
|
|
if (!User.Identity?.IsAuthenticated ?? true)
|
||
|
|
{
|
||
|
|
query = query.Where(e => e.Status == EventStatus.Published);
|
||
|
|
}
|
||
|
|
|
||
|
|
var events = await query
|
||
|
|
.OrderBy(e => e.EventDate)
|
||
|
|
.ToListAsync();
|
||
|
|
|
||
|
|
return Ok(events.Select(MapToEventDto));
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpGet("{id}")]
|
||
|
|
[AllowAnonymous]
|
||
|
|
public async Task<ActionResult<EventDto>> GetEvent(Guid id)
|
||
|
|
{
|
||
|
|
var eventEntity = await _context.Events
|
||
|
|
.Include(e => e.Organizer)
|
||
|
|
.Include(e => e.Registrations)
|
||
|
|
.FirstOrDefaultAsync(e => e.Id == id);
|
||
|
|
|
||
|
|
if (eventEntity == null)
|
||
|
|
{
|
||
|
|
return NotFound();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Draft events only visible to organizers
|
||
|
|
if (eventEntity.Status == EventStatus.Draft)
|
||
|
|
{
|
||
|
|
var userId = GetCurrentUserId();
|
||
|
|
if (userId == null || eventEntity.OrganizerId != userId)
|
||
|
|
{
|
||
|
|
return NotFound();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return Ok(MapToEventDto(eventEntity));
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpPut("{id}")]
|
||
|
|
[Authorize(Roles = "Organizer")]
|
||
|
|
public async Task<ActionResult<EventDto>> UpdateEvent(Guid id, UpdateEventRequest request)
|
||
|
|
{
|
||
|
|
var userId = GetCurrentUserId();
|
||
|
|
if (userId == null)
|
||
|
|
{
|
||
|
|
return Unauthorized();
|
||
|
|
}
|
||
|
|
|
||
|
|
var eventEntity = await _context.Events
|
||
|
|
.Include(e => e.Organizer)
|
||
|
|
.FirstOrDefaultAsync(e => e.Id == id);
|
||
|
|
|
||
|
|
if (eventEntity == null)
|
||
|
|
{
|
||
|
|
return NotFound();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Only organizer can update their event
|
||
|
|
if (eventEntity.OrganizerId != userId)
|
||
|
|
{
|
||
|
|
return Forbid();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update fields
|
||
|
|
if (request.Name != null) eventEntity.Name = request.Name;
|
||
|
|
if (request.Description != null) eventEntity.Description = request.Description;
|
||
|
|
if (request.EventDate != null) eventEntity.EventDate = request.EventDate.Value;
|
||
|
|
if (request.Location != null) eventEntity.Location = request.Location;
|
||
|
|
if (request.Status != null) eventEntity.Status = request.Status.Value;
|
||
|
|
if (request.Category != null) eventEntity.Category = request.Category;
|
||
|
|
if (request.Tags != null) eventEntity.Tags = request.Tags;
|
||
|
|
if (request.MaxParticipants != null) eventEntity.MaxParticipants = request.MaxParticipants;
|
||
|
|
|
||
|
|
eventEntity.UpdatedAt = DateTime.UtcNow;
|
||
|
|
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
return Ok(MapToEventDto(eventEntity));
|
||
|
|
}
|
||
|
|
|
||
|
|
[HttpDelete("{id}")]
|
||
|
|
[Authorize(Roles = "Organizer")]
|
||
|
|
public async Task<IActionResult> DeleteEvent(Guid id)
|
||
|
|
{
|
||
|
|
var userId = GetCurrentUserId();
|
||
|
|
if (userId == null)
|
||
|
|
{
|
||
|
|
return Unauthorized();
|
||
|
|
}
|
||
|
|
|
||
|
|
var eventEntity = await _context.Events.FindAsync(id);
|
||
|
|
|
||
|
|
if (eventEntity == null)
|
||
|
|
{
|
||
|
|
return NotFound();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (eventEntity.OrganizerId != userId)
|
||
|
|
{
|
||
|
|
return Forbid();
|
||
|
|
}
|
||
|
|
|
||
|
|
_context.Events.Remove(eventEntity);
|
||
|
|
await _context.SaveChangesAsync();
|
||
|
|
|
||
|
|
return NoContent();
|
||
|
|
}
|
||
|
|
|
||
|
|
private Guid? GetCurrentUserId()
|
||
|
|
{
|
||
|
|
var userIdClaim = User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||
|
|
if (Guid.TryParse(userIdClaim, out var userId))
|
||
|
|
{
|
||
|
|
return userId;
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static EventDto MapToEventDto(Event eventEntity)
|
||
|
|
{
|
||
|
|
return new EventDto
|
||
|
|
{
|
||
|
|
Id = eventEntity.Id,
|
||
|
|
Name = eventEntity.Name,
|
||
|
|
Description = eventEntity.Description,
|
||
|
|
EventDate = eventEntity.EventDate,
|
||
|
|
Location = eventEntity.Location,
|
||
|
|
Status = eventEntity.Status.ToString(),
|
||
|
|
Category = eventEntity.Category,
|
||
|
|
Tags = eventEntity.Tags,
|
||
|
|
MaxParticipants = eventEntity.MaxParticipants,
|
||
|
|
CurrentRegistrations = eventEntity.Registrations?.Count ?? 0,
|
||
|
|
CreatedAt = eventEntity.CreatedAt,
|
||
|
|
UpdatedAt = eventEntity.UpdatedAt,
|
||
|
|
Organizer = new UserSummaryDto
|
||
|
|
{
|
||
|
|
Id = eventEntity.Organizer.Id,
|
||
|
|
Name = eventEntity.Organizer.Name,
|
||
|
|
Email = eventEntity.Organizer.Email
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|