230 lines
8.0 KiB
C#
230 lines
8.0 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using QRRapidoApp.Models.ViewModels;
|
|
using QRRapidoApp.Services;
|
|
using System.Security.Claims;
|
|
|
|
namespace QRRapidoApp.Controllers
|
|
{
|
|
[Authorize]
|
|
public class PremiumController : Controller
|
|
{
|
|
private readonly StripeService _stripeService;
|
|
private readonly IUserService _userService;
|
|
private readonly AdDisplayService _adDisplayService;
|
|
private readonly IConfiguration _config;
|
|
private readonly ILogger<PremiumController> _logger;
|
|
|
|
public PremiumController(StripeService stripeService, IUserService userService, AdDisplayService adDisplayService, IConfiguration config, ILogger<PremiumController> logger)
|
|
{
|
|
_stripeService = stripeService;
|
|
_userService = userService;
|
|
_adDisplayService = adDisplayService;
|
|
_config = config;
|
|
_logger = logger;
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> Upgrade()
|
|
{
|
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return RedirectToAction("Login", "Account");
|
|
}
|
|
|
|
var user = await _userService.GetUserAsync(userId);
|
|
if (user?.IsPremium == true)
|
|
{
|
|
return RedirectToAction("Dashboard");
|
|
}
|
|
|
|
var model = new UpgradeViewModel
|
|
{
|
|
CurrentPlan = "Free",
|
|
PremiumPrice = _config.GetValue<decimal>("Premium:PremiumPrice"),
|
|
Features = _config.GetSection("Premium:Features").Get<Dictionary<string, bool>>() ?? new(),
|
|
RemainingQRs = await _userService.GetDailyQRCountAsync(userId),
|
|
IsAdFreeActive = !await _adDisplayService.ShouldShowAds(userId),
|
|
DaysUntilAdExpiry = (int)((await _adDisplayService.GetAdFreeExpiryDate(userId) - DateTime.UtcNow)?.TotalDays ?? 0)
|
|
};
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> CreateCheckout()
|
|
{
|
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return Json(new { success = false, error = "User not authenticated" });
|
|
}
|
|
|
|
var priceId = _config["Stripe:PriceId"];
|
|
if (string.IsNullOrEmpty(priceId))
|
|
{
|
|
return Json(new { success = false, error = "Stripe not configured" });
|
|
}
|
|
|
|
try
|
|
{
|
|
var checkoutUrl = await _stripeService.CreateCheckoutSessionAsync(userId, priceId);
|
|
return Json(new { success = true, url = checkoutUrl });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, $"Error creating checkout session for user {userId}");
|
|
return Json(new { success = false, error = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> Success(string session_id)
|
|
{
|
|
if (string.IsNullOrEmpty(session_id))
|
|
{
|
|
return RedirectToAction("Upgrade");
|
|
}
|
|
|
|
try
|
|
{
|
|
ViewBag.Success = true;
|
|
ViewBag.SessionId = session_id;
|
|
return View();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, $"Error processing successful payment for session {session_id}");
|
|
return RedirectToAction("Upgrade");
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
public IActionResult Cancel()
|
|
{
|
|
ViewBag.Cancelled = true;
|
|
return View("Upgrade");
|
|
}
|
|
|
|
[HttpPost]
|
|
[AllowAnonymous]
|
|
public async Task<IActionResult> StripeWebhook()
|
|
{
|
|
try
|
|
{
|
|
using var reader = new StreamReader(HttpContext.Request.Body);
|
|
var json = await reader.ReadToEndAsync();
|
|
var signature = Request.Headers["Stripe-Signature"].FirstOrDefault();
|
|
|
|
if (string.IsNullOrEmpty(signature))
|
|
{
|
|
return BadRequest("Missing Stripe signature");
|
|
}
|
|
|
|
await _stripeService.HandleWebhookAsync(json, signature);
|
|
return Ok();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error processing Stripe webhook");
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> Dashboard()
|
|
{
|
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return RedirectToAction("Login", "Account");
|
|
}
|
|
|
|
var user = await _userService.GetUserAsync(userId);
|
|
if (user?.IsPremium != true)
|
|
{
|
|
return RedirectToAction("Upgrade");
|
|
}
|
|
|
|
var model = new PremiumDashboardViewModel
|
|
{
|
|
User = user,
|
|
QRCodesThisMonth = await _userService.GetQRCountThisMonthAsync(userId),
|
|
TotalQRCodes = user.QRHistoryIds?.Count ?? 0,
|
|
SubscriptionStatus = await _stripeService.GetSubscriptionStatusAsync(user.StripeSubscriptionId),
|
|
RecentQRCodes = await _userService.GetUserQRHistoryAsync(userId, 10)
|
|
};
|
|
|
|
// Calculate next billing date (simplified)
|
|
if (user.PremiumExpiresAt.HasValue)
|
|
{
|
|
model.NextBillingDate = user.PremiumExpiresAt.Value.AddDays(-2); // Approximate
|
|
}
|
|
|
|
// QR type statistics
|
|
model.QRTypeStats = model.RecentQRCodes
|
|
.GroupBy(q => q.Type)
|
|
.ToDictionary(g => g.Key, g => g.Count());
|
|
|
|
return View(model);
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> CancelSubscription()
|
|
{
|
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return Json(new { success = false, error = "User not authenticated" });
|
|
}
|
|
|
|
try
|
|
{
|
|
var user = await _userService.GetUserAsync(userId);
|
|
if (user?.StripeSubscriptionId == null)
|
|
{
|
|
return Json(new { success = false, error = "No active subscription found" });
|
|
}
|
|
|
|
var success = await _stripeService.CancelSubscriptionAsync(user.StripeSubscriptionId);
|
|
if (success)
|
|
{
|
|
TempData["Success"] = "Assinatura cancelada com sucesso. Você manterá o acesso premium até o final do período pago.";
|
|
return Json(new { success = true });
|
|
}
|
|
else
|
|
{
|
|
return Json(new { success = false, error = "Failed to cancel subscription" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, $"Error canceling subscription for user {userId}");
|
|
return Json(new { success = false, error = ex.Message });
|
|
}
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> BillingPortal()
|
|
{
|
|
var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userId))
|
|
{
|
|
return RedirectToAction("Login", "Account");
|
|
}
|
|
|
|
try
|
|
{
|
|
// This would create a Stripe billing portal session
|
|
// For now, redirect to dashboard
|
|
return RedirectToAction("Dashboard");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, $"Error creating billing portal for user {userId}");
|
|
return RedirectToAction("Dashboard");
|
|
}
|
|
}
|
|
}
|
|
} |