QrRapido/Controllers/DeveloperController.cs

163 lines
5.8 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Models;
using QRRapidoApp.Services;
using System.Security.Claims;
namespace QRRapidoApp.Controllers
{
[Authorize]
[Route("Developer")]
[Route("es/Developer")]
[Route("en/Developer")]
public class DeveloperController : Controller
{
private readonly IUserService _userService;
private readonly StripeService _stripeService;
private readonly ILogger<DeveloperController> _logger;
public DeveloperController(
IUserService userService,
StripeService stripeService,
ILogger<DeveloperController> logger)
{
_userService = userService;
_stripeService = stripeService;
_logger = logger;
}
[HttpGet("")]
public async Task<IActionResult> Index()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
var user = await _userService.GetUserAsync(userId);
if (user == null) return NotFound();
ViewBag.Culture = GetCulture();
return View(user);
}
[HttpPost("GenerateKey")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> GenerateKey(string keyName)
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
if (string.IsNullOrWhiteSpace(keyName) || keyName.Length > 50)
{
TempData["Error"] = "Nome da chave inválido (máx. 50 caracteres).";
return Redirect(GetDevUrl());
}
var user = await _userService.GetUserAsync(userId);
if (user == null) return NotFound();
if (user.ApiKeys.Count(k => k.IsActive) >= 5)
{
TempData["Error"] = "Limite de 5 chaves ativas atingido. Revogue uma antes de criar outra.";
return Redirect(GetDevUrl());
}
var (rawKey, prefix) = await _userService.GenerateApiKeyAsync(userId, keyName.Trim());
_logger.LogInformation("API key '{Prefix}' generated for user {UserId}", prefix, userId);
TempData["NewKey"] = rawKey;
TempData["NewKeyName"] = keyName.Trim();
return RedirectToAction(nameof(Index));
}
[HttpGet("Pricing")]
public async Task<IActionResult> Pricing()
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
User? user = null;
if (!string.IsNullOrEmpty(userId))
user = await _userService.GetUserAsync(userId);
ViewBag.CurrentTier = user?.ApiSubscription?.EffectiveTier ?? ApiPlanTier.Free;
ViewBag.Culture = GetCulture();
return View();
}
[HttpPost("SubscribeApi")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SubscribeApi(string planTier)
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
if (!Enum.TryParse<ApiPlanTier>(planTier, out var tier) ||
tier == ApiPlanTier.Free ||
tier == ApiPlanTier.Enterprise)
{
TempData["Error"] = "Plano inválido selecionado.";
return Redirect(GetDevUrl("Pricing"));
}
try
{
var baseUrl = $"{Request.Scheme}://{Request.Host}";
var checkoutUrl = await _stripeService.CreateApiSubscriptionCheckoutAsync(userId, tier, baseUrl);
return Redirect(checkoutUrl);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating API subscription checkout for user {UserId}", userId);
TempData["Error"] = "Erro ao criar sessão de pagamento. Tente novamente.";
return Redirect(GetDevUrl("Pricing"));
}
}
[HttpPost("RevokeKey")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RevokeKey(string prefix)
{
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userId)) return Unauthorized();
if (string.IsNullOrWhiteSpace(prefix))
{
TempData["Error"] = "Chave inválida.";
return Redirect(GetDevUrl());
}
var revoked = await _userService.RevokeApiKeyAsync(userId, prefix);
if (revoked)
{
_logger.LogInformation("API key '{Prefix}' revoked by user {UserId}", prefix, userId);
TempData["Success"] = "Chave revogada com sucesso.";
}
else
{
TempData["Error"] = "Chave não encontrada ou já inativa.";
}
return RedirectToAction(nameof(Index));
}
private string GetCulture()
{
var path = Request.Path.Value ?? "";
if (path.StartsWith("/es/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/es", StringComparison.OrdinalIgnoreCase)) return "es";
if (path.StartsWith("/en/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/en", StringComparison.OrdinalIgnoreCase)) return "en";
return "pt-BR";
}
private string GetDevUrl(string action = "")
{
var base_ = GetCulture() switch {
"es" => "/es/Developer",
"en" => "/en/Developer",
_ => "/Developer"
};
return string.IsNullOrEmpty(action) ? base_ : $"{base_}/{action}";
}
}
}