216 lines
7.6 KiB
C#
216 lines
7.6 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using QRRapidoApp.Models.ViewModels;
|
|
using QRRapidoApp.Services;
|
|
using System.Diagnostics;
|
|
using System.Security.Claims;
|
|
using System.Text;
|
|
|
|
namespace QRRapidoApp.Controllers
|
|
{
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
public class QRController : ControllerBase
|
|
{
|
|
private readonly IQRCodeService _qrService;
|
|
private readonly IUserService _userService;
|
|
private readonly AdDisplayService _adService;
|
|
private readonly ILogger<QRController> _logger;
|
|
|
|
public QRController(IQRCodeService qrService, IUserService userService, AdDisplayService adService, ILogger<QRController> logger)
|
|
{
|
|
_qrService = qrService;
|
|
_userService = userService;
|
|
_adService = adService;
|
|
_logger = logger;
|
|
}
|
|
|
|
[HttpPost("GenerateRapid")]
|
|
public async Task<IActionResult> GenerateRapid([FromBody] QRGenerationRequest request)
|
|
{
|
|
var stopwatch = Stopwatch.StartNew();
|
|
|
|
try
|
|
{
|
|
// Quick validations
|
|
if (string.IsNullOrWhiteSpace(request.Content))
|
|
{
|
|
return BadRequest(new { error = "Conteúdo é obrigatório", success = false });
|
|
}
|
|
|
|
if (request.Content.Length > 4000) // Limit to maintain speed
|
|
{
|
|
return BadRequest(new { error = "Conteúdo muito longo. Máximo 4000 caracteres.", success = false });
|
|
}
|
|
|
|
// Check user status
|
|
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
var user = await _userService.GetUserAsync(userId);
|
|
|
|
// Rate limiting for free users
|
|
if (!await CheckRateLimitAsync(userId, user))
|
|
{
|
|
return StatusCode(429, new
|
|
{
|
|
error = "Limite de QR codes atingido",
|
|
upgradeUrl = "/Premium/Upgrade",
|
|
success = false
|
|
});
|
|
}
|
|
|
|
// Configure optimizations based on user
|
|
request.IsPremium = user?.IsPremium == true;
|
|
request.OptimizeForSpeed = true;
|
|
|
|
// Generate QR code
|
|
var result = await _qrService.GenerateRapidAsync(request);
|
|
|
|
if (!result.Success)
|
|
{
|
|
return StatusCode(500, new { error = result.ErrorMessage, success = false });
|
|
}
|
|
|
|
// Update counter for free users
|
|
if (!request.IsPremium && userId != null)
|
|
{
|
|
var remaining = await _userService.DecrementDailyQRCountAsync(userId);
|
|
result.RemainingQRs = remaining;
|
|
}
|
|
|
|
// Save to history if user is logged in (fire and forget)
|
|
if (userId != null)
|
|
{
|
|
_ = Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
await _userService.SaveQRToHistoryAsync(userId, result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error saving QR to history");
|
|
}
|
|
});
|
|
}
|
|
|
|
stopwatch.Stop();
|
|
|
|
// Performance logging
|
|
_logger.LogInformation($"QR Rapido generated in {stopwatch.ElapsedMilliseconds}ms " +
|
|
$"(service: {result.GenerationTimeMs}ms, " +
|
|
$"cache: {result.FromCache}, " +
|
|
$"user: {(request.IsPremium ? "premium" : "free")})");
|
|
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error in rapid QR code generation");
|
|
return StatusCode(500, new { error = "Erro interno do servidor", success = false });
|
|
}
|
|
}
|
|
|
|
[HttpGet("Download/{qrId}")]
|
|
public async Task<IActionResult> Download(string qrId, string format = "png")
|
|
{
|
|
try
|
|
{
|
|
var qrData = await _userService.GetQRDataAsync(qrId);
|
|
if (qrData == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
var contentType = format.ToLower() switch
|
|
{
|
|
"svg" => "image/svg+xml",
|
|
"pdf" => "application/pdf",
|
|
_ => "image/png"
|
|
};
|
|
|
|
var fileName = $"qrrapido-{DateTime.Now:yyyyMMdd-HHmmss}.{format}";
|
|
|
|
if (format.ToLower() == "svg")
|
|
{
|
|
var svgContent = await _qrService.ConvertToSvgAsync(qrData.QRCodeBase64);
|
|
return File(svgContent, contentType, fileName);
|
|
}
|
|
else if (format.ToLower() == "pdf")
|
|
{
|
|
var pdfContent = await _qrService.ConvertToPdfAsync(qrData.QRCodeBase64, qrData.Size);
|
|
return File(pdfContent, contentType, fileName);
|
|
}
|
|
|
|
var imageBytes = Convert.FromBase64String(qrData.QRCodeBase64);
|
|
return File(imageBytes, contentType, fileName);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, $"Error downloading QR {qrId}");
|
|
return StatusCode(500);
|
|
}
|
|
}
|
|
|
|
[HttpPost("SaveToHistory")]
|
|
public async Task<IActionResult> SaveToHistory([FromBody] SaveToHistoryRequest request)
|
|
{
|
|
try
|
|
{
|
|
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var qrData = await _userService.GetQRDataAsync(request.QrId);
|
|
if (qrData == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
// QR is already saved when generated, just return success
|
|
return Ok(new { success = true, message = "QR Code salvo no histórico!" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error saving QR to history");
|
|
return StatusCode(500, new { error = "Erro ao salvar no histórico." });
|
|
}
|
|
}
|
|
|
|
[HttpGet("History")]
|
|
public async Task<IActionResult> GetHistory(int limit = 20)
|
|
{
|
|
try
|
|
{
|
|
var userId = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var history = await _userService.GetUserQRHistoryAsync(userId, limit);
|
|
return Ok(history);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting QR history");
|
|
return StatusCode(500);
|
|
}
|
|
}
|
|
|
|
private async Task<bool> CheckRateLimitAsync(string? userId, Models.User? user)
|
|
{
|
|
if (user?.IsPremium == true) return true;
|
|
|
|
var dailyLimit = userId != null ? 50 : 10; // Logged in: 50/day, Anonymous: 10/day
|
|
var currentCount = await _userService.GetDailyQRCountAsync(userId);
|
|
|
|
return currentCount < dailyLimit;
|
|
}
|
|
}
|
|
|
|
public class SaveToHistoryRequest
|
|
{
|
|
public string QrId { get; set; } = string.Empty;
|
|
}
|
|
} |