using Microsoft.AspNetCore.Mvc; using QRRapidoApp.Data; using QRRapidoApp.Models; using MongoDB.Driver; namespace QRRapidoApp.Controllers { /// /// Admin controller - ONLY accessible from localhost for security /// [ApiController] [Route("api/[controller]")] public class AdminController : ControllerBase { private readonly MongoDbContext _context; private readonly ILogger _logger; public AdminController(MongoDbContext context, ILogger logger) { _context = context; _logger = logger; } /// /// Seed/Update MongoDB Plans collection /// Only accessible from localhost (127.0.0.1 or ::1) /// [HttpPost("SeedPlans")] public async Task SeedPlans([FromBody] List plans) { // SECURITY: Only allow from localhost var remoteIp = HttpContext.Connection.RemoteIpAddress; var isLocalhost = remoteIp != null && (remoteIp.ToString() == "127.0.0.1" || remoteIp.ToString() == "::1" || remoteIp.ToString() == "localhost"); if (!isLocalhost) { _logger.LogWarning($"Unauthorized admin access attempt from {remoteIp}"); return Forbid("This endpoint is only accessible from localhost"); } try { _logger.LogInformation($"SeedPlans called from localhost - Upserting {plans.Count} plans"); foreach (var plan in plans) { // Upsert based on interval (month/year) var filter = Builders.Filter.Eq(p => p.Interval, plan.Interval); var options = new ReplaceOptions { IsUpsert = true }; await _context.Plans.ReplaceOneAsync(filter, plan, options); _logger.LogInformation($"Upserted plan: {plan.Interval}"); } return Ok(new { success = true, message = $"{plans.Count} plans seeded successfully", plans = plans.Select(p => new { interval = p.Interval, priceIds = p.PricesByCountry.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.StripePriceId ) }) }); } catch (Exception ex) { _logger.LogError(ex, "Error seeding plans"); return StatusCode(500, new { success = false, error = ex.Message }); } } /// /// Get all plans from MongoDB /// Only accessible from localhost /// [HttpGet("Plans")] public async Task GetPlans() { // SECURITY: Only allow from localhost var remoteIp = HttpContext.Connection.RemoteIpAddress; var isLocalhost = remoteIp != null && (remoteIp.ToString() == "127.0.0.1" || remoteIp.ToString() == "::1" || remoteIp.ToString() == "localhost"); if (!isLocalhost) { _logger.LogWarning($"Unauthorized admin access attempt from {remoteIp}"); return Forbid("This endpoint is only accessible from localhost"); } try { var plans = await _context.Plans.Find(_ => true).ToListAsync(); return Ok(new { success = true, count = plans.Count, plans }); } catch (Exception ex) { _logger.LogError(ex, "Error retrieving plans"); return StatusCode(500, new { success = false, error = ex.Message }); } } /// /// Delete all plans from MongoDB /// Only accessible from localhost /// [HttpDelete("Plans")] public async Task DeleteAllPlans() { // SECURITY: Only allow from localhost var remoteIp = HttpContext.Connection.RemoteIpAddress; var isLocalhost = remoteIp != null && (remoteIp.ToString() == "127.0.0.1" || remoteIp.ToString() == "::1" || remoteIp.ToString() == "localhost"); if (!isLocalhost) { _logger.LogWarning($"Unauthorized admin access attempt from {remoteIp}"); return Forbid("This endpoint is only accessible from localhost"); } try { var result = await _context.Plans.DeleteManyAsync(_ => true); _logger.LogInformation($"Deleted {result.DeletedCount} plans"); return Ok(new { success = true, deletedCount = result.DeletedCount }); } catch (Exception ex) { _logger.LogError(ex, "Error deleting plans"); return StatusCode(500, new { success = false, error = ex.Message }); } } } }