From 9a850d239f3f95c10bb931e6b475e03f9991e2a7 Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Tue, 9 Sep 2025 19:13:21 -0300 Subject: [PATCH] fix: Ajustes de cache e planos --- .gitea/workflows/deploy-bcards.yml | 102 ++++++++++++++++++ src/BCards.Web/Controllers/HomeController.cs | 24 ++++- .../Middleware/AuthCacheMiddleware.cs | 71 ++++++++++++ src/BCards.Web/Program.cs | 2 + 4 files changed, 197 insertions(+), 2 deletions(-) create mode 100644 src/BCards.Web/Middleware/AuthCacheMiddleware.cs diff --git a/.gitea/workflows/deploy-bcards.yml b/.gitea/workflows/deploy-bcards.yml index b055183..a7b3c04 100644 --- a/.gitea/workflows/deploy-bcards.yml +++ b/.gitea/workflows/deploy-bcards.yml @@ -218,6 +218,108 @@ jobs: "FromEmail": "${{ vars.SENDGRID_FROM_EMAIL || 'ricardo.carneiro@jobmaker.com.br' }}", "FromName": "${{ vars.SENDGRID_FROM_NAME || 'Ricardo Carneiro' }}" }, + "Plans": { + "Basic": { + "Name": "Básico", + "PriceId": "price_1RycPaBMIadsOxJVKioZZofK", + "Price": 5.90, + "MaxPages": 3, + "MaxLinks": 8, + "AllowPremiumThemes": false, + "AllowProductLinks": false, + "AllowAnalytics": true, + "Features": [ "URL Personalizada", "20 temas básicos", "Analytics simples" ], + "Interval": "month" + }, + "Professional": { + "Name": "Profissional", + "PriceId": "price_1RycQmBMIadsOxJVGqjVMaOj", + "Price": 12.90, + "MaxPages": 5, + "MaxLinks": 20, + "AllowPremiumThemes": false, + "AllowProductLinks": false, + "AllowAnalytics": true, + "Features": [ "URL Personalizada", "20 temas básicos", "Analytics avançado" ], + "Interval": "month" + }, + "Premium": { + "Name": "Premium", + "PriceId": "price_1RycRUBMIadsOxJVkxGOh3uu", + "Price": 19.90, + "MaxPages": 15, + "MaxLinks": -1, + "AllowPremiumThemes": true, + "AllowProductLinks": false, + "AllowAnalytics": true, + "SpecialModeration": false, + "Features": [ "URL Personalizada", "40 temas (básicos + premium)", "Suporte prioritário", "Links ilimitados" ], + "Interval": "month" + }, + "PremiumAffiliate": { + "Name": "Premium+Afiliados", + "PriceId": "price_1RycTaBMIadsOxJVeDLseXQq", + "Price": 29.90, + "MaxPages": 15, + "MaxLinks": -1, + "AllowPremiumThemes": true, + "AllowProductLinks": true, + "AllowAnalytics": true, + "SpecialModeration": true, + "Features": [ "Tudo do Premium", "Links de produto", "Moderação especial", "Até 10 links afiliados" ], + "Interval": "month" + }, + "BasicYearly": { + "Name": "Básico Anual", + "PriceId": "price_1RycWgBMIadsOxJVGdtEeoMS", + "Price": 59.00, + "MaxPages": 3, + "MaxLinks": 8, + "AllowPremiumThemes": false, + "AllowProductLinks": false, + "AllowAnalytics": true, + "Features": [ "URL Personalizada", "20 temas básicos", "Analytics simples", "Economize R$ 11,80 (2 meses grátis)" ], + "Interval": "year" + }, + "ProfessionalYearly": { + "Name": "Profissional Anual", + "PriceId": "price_1RycXdBMIadsOxJV5cNX7dHm", + "Price": 129.00, + "MaxPages": 5, + "MaxLinks": 20, + "AllowPremiumThemes": false, + "AllowProductLinks": false, + "AllowAnalytics": true, + "Features": [ "URL Personalizada", "20 temas básicos", "Analytics avançado", "Economize R$ 25,80 (2 meses grátis)" ], + "Interval": "year" + }, + "PremiumYearly": { + "Name": "Premium Anual", + "PriceId": "price_1RycYnBMIadsOxJVPdKmzy4m", + "Price": 199.00, + "MaxPages": 15, + "MaxLinks": -1, + "AllowPremiumThemes": true, + "AllowProductLinks": false, + "AllowAnalytics": true, + "SpecialModeration": false, + "Features": [ "URL Personalizada", "40 temas (básicos + premium)", "Suporte prioritário", "Links ilimitados", "Economize R$ 39,80 (2 meses grátis)" ], + "Interval": "year" + }, + "PremiumAffiliateYearly": { + "Name": "Premium+Afiliados Anual", + "PriceId": "price_1RycaEBMIadsOxJVEhsdB2Y1", + "Price": 299.00, + "MaxPages": 15, + "MaxLinks": -1, + "AllowPremiumThemes": true, + "AllowProductLinks": true, + "AllowAnalytics": true, + "SpecialModeration": true, + "Features": [ "Tudo do Premium", "Links de produto", "Moderação especial", "Até 10 links afiliados", "Economize R$ 59,80 (2 meses grátis)" ], + "Interval": "year" + } + }, "Moderation": { "PriorityTimeframes": { "Trial": "7.00:00:00", diff --git a/src/BCards.Web/Controllers/HomeController.cs b/src/BCards.Web/Controllers/HomeController.cs index d713a5c..e5fe2a7 100644 --- a/src/BCards.Web/Controllers/HomeController.cs +++ b/src/BCards.Web/Controllers/HomeController.cs @@ -21,9 +21,19 @@ public class HomeController : Controller _stripeSettings = stripeSettings.Value; } - [ResponseCache(Duration = 600, Location = ResponseCacheLocation.Any)] // 10 minutos public async Task Index() { + // Cache condicional: apenas para usuários não logados + if (User.Identity?.IsAuthenticated != true) + { + Response.Headers["Cache-Control"] = "public, max-age=600"; // 10 minutos + } + else + { + Response.Headers["Cache-Control"] = "no-cache, must-revalidate"; + Response.Headers["Vary"] = "Cookie"; + } + ViewBag.IsHomePage = true; // Flag para identificar home ViewBag.Categories = await _categoryService.GetAllCategoriesAsync(); ViewBag.RecentPages = await _userPageService.GetRecentPagesAsync(6); @@ -39,9 +49,19 @@ public class HomeController : Controller } [Route("Pricing")] - [ResponseCache(Duration = 1800, Location = ResponseCacheLocation.Any)] // 30 minutos public IActionResult Pricing() { + // Cache condicional: apenas para usuários não logados + if (User.Identity?.IsAuthenticated != true) + { + Response.Headers["Cache-Control"] = "public, max-age=1800"; // 30 minutos + } + else + { + Response.Headers["Cache-Control"] = "no-cache, must-revalidate"; + Response.Headers["Vary"] = "Cookie"; + } + ViewBag.IsHomePage = true; return View(); } diff --git a/src/BCards.Web/Middleware/AuthCacheMiddleware.cs b/src/BCards.Web/Middleware/AuthCacheMiddleware.cs new file mode 100644 index 0000000..387557f --- /dev/null +++ b/src/BCards.Web/Middleware/AuthCacheMiddleware.cs @@ -0,0 +1,71 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System.Threading.Tasks; + +namespace BCards.Web.Middleware +{ + /// + /// Middleware para garantir que páginas que exibem conteúdo dependente de autenticação + /// tenham os headers de cache corretos para evitar problemas de cache do menu + /// + public class AuthCacheMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public AuthCacheMiddleware(RequestDelegate next, ILogger logger) + { + _next = next; + _logger = logger; + } + + public async Task InvokeAsync(HttpContext context) + { + await _next(context); + + // Aplicar headers apenas para páginas HTML (não APIs, imagens, etc) + if (context.Response.ContentType?.StartsWith("text/html") == true) + { + var path = context.Request.Path.Value?.ToLower() ?? string.Empty; + + // Páginas que sempre mostram menu com estado de autenticação + bool isPageWithAuthMenu = path == "/" || + path.StartsWith("/home") || + path == "/pricing" || + path.StartsWith("/planos") || + path.StartsWith("/admin") || + path.StartsWith("/payment") || + path.StartsWith("/subscription"); + + if (isPageWithAuthMenu) + { + // Se usuário está logado, garantir que não use cache + if (context.User?.Identity?.IsAuthenticated == true) + { + // Só adicionar se não foi definido explicitamente pelo controller + if (!context.Response.Headers.ContainsKey("Cache-Control")) + { + context.Response.Headers["Cache-Control"] = "no-cache, must-revalidate"; + context.Response.Headers["Vary"] = "Cookie"; + + _logger.LogDebug("AuthCache: Applied no-cache for authenticated user on {Path}", path); + } + } + else + { + // Para usuários não logados, garantir Vary: Cookie para cache adequado + if (!context.Response.Headers.ContainsKey("Vary") || + !context.Response.Headers["Vary"].ToString().Contains("Cookie")) + { + var existingVary = context.Response.Headers["Vary"].ToString(); + var newVary = string.IsNullOrEmpty(existingVary) ? "Cookie" : $"{existingVary}, Cookie"; + context.Response.Headers["Vary"] = newVary; + + _logger.LogDebug("AuthCache: Added Vary: Cookie for anonymous user on {Path}", path); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/src/BCards.Web/Program.cs b/src/BCards.Web/Program.cs index 3f17430..e36a0fd 100644 --- a/src/BCards.Web/Program.cs +++ b/src/BCards.Web/Program.cs @@ -555,6 +555,8 @@ app.UseRequestLocalization(); app.UseAuthentication(); app.UseAuthorization(); +app.UseMiddleware(); +app.UseMiddleware(); app.UseMiddleware(); app.UseMiddleware(); app.UseMiddleware();