QrRapido/Controllers/AdminController.cs
Ricardo Carneiro 16a9720a12
All checks were successful
Deploy QR Rapido / test (push) Successful in 59s
Deploy QR Rapido / build-and-push (push) Successful in 9m57s
Deploy QR Rapido / deploy-staging (push) Has been skipped
Deploy QR Rapido / deploy-production (push) Successful in 2m11s
feat: qrcode por creditos.
2026-01-26 20:13:45 -03:00

213 lines
7.6 KiB
C#

using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Data;
using QRRapidoApp.Models;
using QRRapidoApp.Services;
using MongoDB.Driver;
using System.Security.Claims;
namespace QRRapidoApp.Controllers
{
public class AdminController : Controller
{
private readonly MongoDbContext _context;
private readonly ILogger<AdminController> _logger;
private readonly IConfiguration _config;
private readonly IUserService _userService;
public AdminController(MongoDbContext context, ILogger<AdminController> logger, IConfiguration config, IUserService userService)
{
_context = context;
_logger = logger;
_config = config;
_userService = userService;
}
private bool IsAdmin()
{
// 1. Check if authenticated
if (User?.Identity?.IsAuthenticated != true) return false;
// 2. Get User Email
var userEmail = User.FindFirst(ClaimTypes.Email)?.Value;
if (string.IsNullOrEmpty(userEmail))
{
// Fallback: try to find user by ID to get email
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!string.IsNullOrEmpty(userId))
{
var user = _userService.GetUserAsync(userId).Result;
userEmail = user?.Email;
}
}
if (string.IsNullOrEmpty(userEmail)) return false;
// 3. Check against AllowedEmails list
var allowedEmails = _config.GetSection("Admin:AllowedEmails").Get<List<string>>() ?? new List<string>();
return allowedEmails.Contains(userEmail, StringComparer.OrdinalIgnoreCase);
}
private bool IsLocalhost()
{
var remoteIp = HttpContext.Connection.RemoteIpAddress;
return remoteIp != null &&
(remoteIp.ToString() == "127.0.0.1" ||
remoteIp.ToString() == "::1" ||
remoteIp.ToString() == "localhost");
}
// --- View Actions ---
[HttpGet("/Admin")]
public async Task<IActionResult> Index()
{
if (!IsAdmin()) return RedirectToAction("Index", "Home");
try
{
var orders = await _context.Orders
.Find(o => o.Status == "Pending")
.SortByDescending(o => o.CreatedAt)
.ToListAsync();
return View(orders);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching pending orders for view");
return View(new List<Order>());
}
}
// --- API Endpoints ---
[HttpGet("api/Admin/Orders/Pending")]
public async Task<IActionResult> GetPendingOrders()
{
if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");
try
{
var orders = await _context.Orders
.Find(o => o.Status == "Pending")
.SortByDescending(o => o.CreatedAt)
.ToListAsync();
return Ok(orders);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching pending orders");
return StatusCode(500, new { error = "Internal server error" });
}
}
[HttpPost("api/Admin/Orders/{orderId}/Approve")]
public async Task<IActionResult> ApproveOrder(string orderId)
{
if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");
try
{
var adminEmail = User.FindFirst(ClaimTypes.Email)?.Value ?? "unknown_admin";
// 1. Get the order
var order = await _context.Orders
.Find(o => o.Id == orderId)
.FirstOrDefaultAsync();
if (order == null) return NotFound("Order not found");
if (order.Status == "Paid") return BadRequest("Order already paid");
// 2. Update Order Status
var updateOrder = Builders<Order>.Update
.Set(o => o.Status, "Paid")
.Set(o => o.PaidAt, DateTime.UtcNow)
.Set(o => o.ApprovedBy, adminEmail);
await _context.Orders.UpdateOneAsync(o => o.Id == orderId, updateOrder);
// 3. Add Credits to User
var userUpdate = Builders<User>.Update.Inc(u => u.Credits, order.CreditsAmount);
await _context.Users.UpdateOneAsync(u => u.Id == order.UserId, userUpdate);
_logger.LogInformation($"Order {orderId} approved by {adminEmail}. {order.CreditsAmount} credits added to user {order.UserId}");
return Ok(new { success = true, message = "Order approved and credits added." });
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error approving order {orderId}");
return StatusCode(500, new { error = "Internal server error" });
}
}
[HttpPost("api/Admin/Orders/{orderId}/Reject")]
public async Task<IActionResult> RejectOrder(string orderId)
{
if (!IsAdmin()) return Unauthorized("Access denied. Admin rights required.");
try
{
var adminEmail = User.FindFirst(ClaimTypes.Email)?.Value ?? "unknown_admin";
var update = Builders<Order>.Update
.Set(o => o.Status, "Rejected")
.Set(o => o.ApprovedBy, adminEmail); // Rejected by...
var result = await _context.Orders.UpdateOneAsync(o => o.Id == orderId, update);
if (result.ModifiedCount == 0) return NotFound("Order not found");
_logger.LogInformation($"Order {orderId} rejected by {adminEmail}");
return Ok(new { success = true, message = "Order rejected." });
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error rejecting order {orderId}");
return StatusCode(500, new { error = "Internal server error" });
}
}
// --- Legacy Localhost-Only Endpoints ---
[HttpPost("api/Admin/SeedPlans")]
public async Task<IActionResult> SeedPlans([FromBody] List<Plan> plans)
{
if (!IsLocalhost()) return Forbid("Localhost only");
try
{
foreach (var plan in plans)
{
var filter = Builders<Plan>.Filter.Eq(p => p.Interval, plan.Interval);
var options = new ReplaceOptions { IsUpsert = true };
await _context.Plans.ReplaceOneAsync(filter, plan, options);
}
return Ok(new { success = true, message = "Plans seeded" });
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
[HttpGet("api/Admin/Plans")]
public async Task<IActionResult> GetPlans()
{
if (!IsLocalhost()) return Forbid("Localhost only");
var plans = await _context.Plans.Find(_ => true).ToListAsync();
return Ok(new { success = true, plans });
}
[HttpDelete("api/Admin/Plans")]
public async Task<IActionResult> DeleteAllPlans()
{
if (!IsLocalhost()) return Forbid("Localhost only");
await _context.Plans.DeleteManyAsync(_ => true);
return Ok(new { success = true });
}
}
}