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 AnnouncementsController : ControllerBase { private readonly RacePlannerDbContext _context; public AnnouncementsController(RacePlannerDbContext context) { _context = context; } [HttpPost] [Authorize(Roles = "Organizer")] public async Task> CreateAnnouncement(CreateAnnouncementRequest request) { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(); } // Verify event exists and user is organizer var eventEntity = await _context.Events .FirstOrDefaultAsync(e => e.Id == request.EventId); if (eventEntity == null) { return NotFound(new { error = "Event not found" }); } if (eventEntity.OrganizerId != userId.Value) { return Forbid(); } var announcement = new Announcement { EventId = request.EventId, Title = request.Title, Content = request.Content, AuthorId = userId.Value, IsPublished = true }; _context.Announcements.Add(announcement); await _context.SaveChangesAsync(); // Load related data await _context.Entry(announcement) .Reference(a => a.Event) .LoadAsync(); await _context.Entry(announcement) .Reference(a => a.Author) .LoadAsync(); // TODO: Send notifications to registered participants (Task 7.7) return CreatedAtAction( nameof(GetAnnouncement), new { id = announcement.Id }, MapToAnnouncementDto(announcement)); } [HttpGet("{id}")] public async Task> GetAnnouncement(Guid id) { var announcement = await _context.Announcements .Include(a => a.Event) .Include(a => a.Author) .FirstOrDefaultAsync(a => a.Id == id); if (announcement == null) { return NotFound(); } // Only show published announcements to participants if (!announcement.IsPublished) { var userId = GetCurrentUserId(); if (userId == null || announcement.Event.OrganizerId != userId.Value) { return NotFound(); } } return Ok(MapToAnnouncementDto(announcement)); } [HttpGet("event/{eventId}")] public async Task>> GetEventAnnouncements(Guid eventId) { var userId = GetCurrentUserId(); var isOrganizer = false; if (userId != null) { isOrganizer = await _context.Events .AnyAsync(e => e.Id == eventId && e.OrganizerId == userId.Value); } var query = _context.Announcements .Include(a => a.Event) .Include(a => a.Author) .Where(a => a.EventId == eventId) .AsQueryable(); // Only show published announcements to non-organizers if (!isOrganizer) { query = query.Where(a => a.IsPublished); } var announcements = await query .OrderByDescending(a => a.CreatedAt) .ToListAsync(); return Ok(announcements.Select(MapToAnnouncementDto)); } [HttpPut("{id}")] [Authorize(Roles = "Organizer")] public async Task> UpdateAnnouncement(Guid id, UpdateAnnouncementRequest request) { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(); } var announcement = await _context.Announcements .Include(a => a.Event) .Include(a => a.Author) .FirstOrDefaultAsync(a => a.Id == id); if (announcement == null) { return NotFound(); } // Only organizer can update if (announcement.Event.OrganizerId != userId.Value) { return Forbid(); } // Update fields if (request.Title != null) announcement.Title = request.Title; if (request.Content != null) announcement.Content = request.Content; if (request.IsPublished.HasValue) announcement.IsPublished = request.IsPublished.Value; announcement.UpdatedAt = DateTime.UtcNow; await _context.SaveChangesAsync(); return Ok(MapToAnnouncementDto(announcement)); } [HttpDelete("{id}")] [Authorize(Roles = "Organizer")] public async Task DeleteAnnouncement(Guid id) { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(); } var announcement = await _context.Announcements .Include(a => a.Event) .FirstOrDefaultAsync(a => a.Id == id); if (announcement == null) { return NotFound(); } // Only organizer can delete if (announcement.Event.OrganizerId != userId.Value) { return Forbid(); } _context.Announcements.Remove(announcement); await _context.SaveChangesAsync(); return NoContent(); } [HttpGet("my-announcements")] public async Task>> GetMyAnnouncements() { var userId = GetCurrentUserId(); if (userId == null) { return Unauthorized(); } // Get user registrations var userRegistrationEventIds = await _context.Registrations .Where(r => r.ParticipantId == userId.Value && r.Status != RegistrationStatus.Cancelled) .Select(r => r.EventId) .ToListAsync(); // Get announcements for those events var announcements = await _context.Announcements .Include(a => a.Event) .Include(a => a.Author) .Where(a => userRegistrationEventIds.Contains(a.EventId) && a.IsPublished) .OrderByDescending(a => a.CreatedAt) .ToListAsync(); return Ok(announcements.Select(MapToAnnouncementDto)); } 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 AnnouncementDto MapToAnnouncementDto(Announcement announcement) { return new AnnouncementDto { Id = announcement.Id, EventId = announcement.EventId, EventName = announcement.Event?.Name ?? string.Empty, Title = announcement.Title, Content = announcement.Content, AuthorId = announcement.AuthorId, AuthorName = announcement.Author?.Name ?? string.Empty, CreatedAt = announcement.CreatedAt, UpdatedAt = announcement.UpdatedAt, IsPublished = announcement.IsPublished }; } }