using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using SlpModularCms.Modules.Offerings.Models; using SlpModularCms.Modules.Offerings.Services; namespace SlpModularCms.Modules.Offerings.Controllers; [ApiController] [Route("offerings")] [Authorize(Policy = "AdminOnly")] public class OfferingsController(IOfferingsService service) : ControllerBase { [HttpGet] [AllowAnonymous] [EnableRateLimiting("offerings-public")] public async Task GetOfferings() { var offerings = await service.GetPublicOfferingsAsync(); return Ok(offerings); } [HttpGet("admin")] public async Task GetAllForAdmin() { var offerings = await service.GetAllForAdminAsync(); return Ok(offerings); } [HttpPost("admin")] public async Task Create([FromBody] CreateOfferingRequest request) { try { var dto = await service.CreateAsync(request, GetCallerId()); return CreatedAtAction(nameof(GetAllForAdmin), null, dto); } catch (OfferingSlugConflictException ex) { return Conflict(new ProblemDetails { Status = StatusCodes.Status409Conflict, Title = ex.Message }); } } [HttpPut("admin/{id:guid}")] public async Task Update(Guid id, [FromBody] UpdateOfferingRequest request) { try { var dto = await service.UpdateAsync(id, request, GetCallerId()); return dto is null ? NotFound() : Ok(dto); } catch (OfferingSlugConflictException ex) { return Conflict(new ProblemDetails { Status = StatusCodes.Status409Conflict, Title = ex.Message }); } } [HttpDelete("admin/{id:guid}")] public async Task Delete(Guid id) { var deleted = await service.DeleteAsync(id, GetCallerId()); return deleted ? NoContent() : NotFound(); } [HttpPut("admin/reorder")] public async Task Reorder([FromBody] ReorderOfferingsRequest request) { await service.ReorderAsync(request.OrderedIds, GetCallerId()); return NoContent(); } [HttpPost("admin/{id:guid}/move-up")] public async Task MoveUp(Guid id) { await service.MoveUpAsync(id, GetCallerId()); return NoContent(); } [HttpPost("admin/{id:guid}/move-down")] public async Task MoveDown(Guid id) { await service.MoveDownAsync(id, GetCallerId()); return NoContent(); } private Guid GetCallerId() { var claim = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"); return Guid.TryParse(claim, out var id) ? id : Guid.Empty; } }