fix: Ajustes de cache e planos
All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 2s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 15m3s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 2m22s
BCards Deployment Pipeline / Deploy to Staging (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 2s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 15m3s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 2m22s
BCards Deployment Pipeline / Deploy to Staging (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
This commit is contained in:
parent
61453b65c9
commit
9a850d239f
@ -218,6 +218,108 @@ jobs:
|
|||||||
"FromEmail": "${{ vars.SENDGRID_FROM_EMAIL || 'ricardo.carneiro@jobmaker.com.br' }}",
|
"FromEmail": "${{ vars.SENDGRID_FROM_EMAIL || 'ricardo.carneiro@jobmaker.com.br' }}",
|
||||||
"FromName": "${{ vars.SENDGRID_FROM_NAME || 'Ricardo Carneiro' }}"
|
"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": {
|
"Moderation": {
|
||||||
"PriorityTimeframes": {
|
"PriorityTimeframes": {
|
||||||
"Trial": "7.00:00:00",
|
"Trial": "7.00:00:00",
|
||||||
|
|||||||
@ -21,9 +21,19 @@ public class HomeController : Controller
|
|||||||
_stripeSettings = stripeSettings.Value;
|
_stripeSettings = stripeSettings.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ResponseCache(Duration = 600, Location = ResponseCacheLocation.Any)] // 10 minutos
|
|
||||||
public async Task<IActionResult> Index()
|
public async Task<IActionResult> 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.IsHomePage = true; // Flag para identificar home
|
||||||
ViewBag.Categories = await _categoryService.GetAllCategoriesAsync();
|
ViewBag.Categories = await _categoryService.GetAllCategoriesAsync();
|
||||||
ViewBag.RecentPages = await _userPageService.GetRecentPagesAsync(6);
|
ViewBag.RecentPages = await _userPageService.GetRecentPagesAsync(6);
|
||||||
@ -39,9 +49,19 @@ public class HomeController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("Pricing")]
|
[Route("Pricing")]
|
||||||
[ResponseCache(Duration = 1800, Location = ResponseCacheLocation.Any)] // 30 minutos
|
|
||||||
public IActionResult Pricing()
|
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;
|
ViewBag.IsHomePage = true;
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/BCards.Web/Middleware/AuthCacheMiddleware.cs
Normal file
71
src/BCards.Web/Middleware/AuthCacheMiddleware.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BCards.Web.Middleware
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// </summary>
|
||||||
|
public class AuthCacheMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly ILogger<AuthCacheMiddleware> _logger;
|
||||||
|
|
||||||
|
public AuthCacheMiddleware(RequestDelegate next, ILogger<AuthCacheMiddleware> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -555,6 +555,8 @@ app.UseRequestLocalization();
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.UseMiddleware<BCards.Web.Middleware.SmartCacheMiddleware>();
|
||||||
|
app.UseMiddleware<BCards.Web.Middleware.AuthCacheMiddleware>();
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PlanLimitationMiddleware>();
|
app.UseMiddleware<BCards.Web.Middleware.PlanLimitationMiddleware>();
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PageStatusMiddleware>();
|
app.UseMiddleware<BCards.Web.Middleware.PageStatusMiddleware>();
|
||||||
app.UseMiddleware<BCards.Web.Middleware.PreviewTokenMiddleware>();
|
app.UseMiddleware<BCards.Web.Middleware.PreviewTokenMiddleware>();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user