fix: bug para excluir trial
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 8m1s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 3m48s
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 8m1s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 3m48s
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
55ad73b505
commit
aea64c0b8e
@ -30,40 +30,44 @@ public class SitemapController : Controller
|
|||||||
// 🔥 NOVA FUNCIONALIDADE: Usar LivePages em vez de UserPages
|
// 🔥 NOVA FUNCIONALIDADE: Usar LivePages em vez de UserPages
|
||||||
var livePages = await _livePageService.GetAllActiveAsync();
|
var livePages = await _livePageService.GetAllActiveAsync();
|
||||||
|
|
||||||
|
// Define namespace corretamente para evitar conflitos
|
||||||
|
XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
|
||||||
|
|
||||||
|
// Construir URLs das páginas dinâmicas separadamente para evitar problemas
|
||||||
|
var dynamicUrls = livePages.Select(page =>
|
||||||
|
new XElement(ns + "url",
|
||||||
|
new XElement(ns + "loc", $"{Request.Scheme}://{Request.Host}/page/{page.Category?.Replace(" ", "-")?.ToLower()}/{page.Slug}"),
|
||||||
|
new XElement(ns + "lastmod", page.LastSyncAt.ToString("yyyy-MM-dd")),
|
||||||
|
new XElement(ns + "changefreq", "weekly"),
|
||||||
|
new XElement(ns + "priority", "0.8")
|
||||||
|
)
|
||||||
|
).ToList();
|
||||||
|
|
||||||
var sitemap = new XDocument(
|
var sitemap = new XDocument(
|
||||||
new XDeclaration("1.0", "utf-8", "yes"),
|
new XDeclaration("1.0", "utf-8", "yes"),
|
||||||
new XElement("urlset",
|
new XElement(ns + "urlset",
|
||||||
new XAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"),
|
|
||||||
|
|
||||||
// Add static pages
|
// Add static pages
|
||||||
new XElement("url",
|
new XElement(ns + "url",
|
||||||
new XElement("loc", $"{Request.Scheme}://{Request.Host}/"),
|
new XElement(ns + "loc", $"{Request.Scheme}://{Request.Host}/"),
|
||||||
new XElement("lastmod", DateTime.UtcNow.ToString("yyyy-MM-dd")),
|
new XElement(ns + "lastmod", DateTime.UtcNow.ToString("yyyy-MM-dd")),
|
||||||
new XElement("changefreq", "daily"),
|
new XElement(ns + "changefreq", "daily"),
|
||||||
new XElement("priority", "1.0")
|
new XElement(ns + "priority", "1.0")
|
||||||
),
|
),
|
||||||
new XElement("url",
|
new XElement(ns + "url",
|
||||||
new XElement("loc", $"{Request.Scheme}://{Request.Host}/Home/Pricing"),
|
new XElement(ns + "loc", $"{Request.Scheme}://{Request.Host}/Home/Pricing"),
|
||||||
new XElement("lastmod", DateTime.UtcNow.ToString("yyyy-MM-dd")),
|
new XElement(ns + "lastmod", DateTime.UtcNow.ToString("yyyy-MM-dd")),
|
||||||
new XElement("changefreq", "weekly"),
|
new XElement(ns + "changefreq", "weekly"),
|
||||||
new XElement("priority", "0.9")
|
new XElement(ns + "priority", "0.9")
|
||||||
),
|
),
|
||||||
|
|
||||||
// Add live pages (SEO-optimized URLs only)
|
// Add live pages (SEO-optimized URLs only)
|
||||||
livePages.Select(page =>
|
dynamicUrls
|
||||||
new XElement("url",
|
|
||||||
new XElement("loc", $"{Request.Scheme}://{Request.Host}/page/{page.Category}/{page.Slug}"),
|
|
||||||
new XElement("lastmod", page.LastSyncAt.ToString("yyyy-MM-dd")),
|
|
||||||
new XElement("changefreq", "weekly"),
|
|
||||||
new XElement("priority", "0.8")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
_logger.LogInformation($"Generated sitemap with {livePages.Count} live pages");
|
_logger.LogInformation($"Generated sitemap with {livePages.Count} live pages");
|
||||||
|
|
||||||
return Content(sitemap.ToString(), "application/xml", Encoding.UTF8);
|
return Content(sitemap.ToString(SaveOptions.DisableFormatting), "application/xml", Encoding.UTF8);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -20,67 +20,110 @@ public class TrialExpirationService : BackgroundService
|
|||||||
|
|
||||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("TrialExpirationService started");
|
||||||
|
|
||||||
while (!stoppingToken.IsCancellationRequested)
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ProcessTrialExpirationsAsync();
|
await ProcessTrialExpirationsAsync();
|
||||||
|
|
||||||
|
// Verificar cancelamento antes de fazer delay
|
||||||
|
if (stoppingToken.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
await Task.Delay(_checkInterval, stoppingToken);
|
await Task.Delay(_checkInterval, stoppingToken);
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Cancelamento normal - não é erro
|
||||||
|
_logger.LogInformation("TrialExpirationService is being cancelled");
|
||||||
|
break;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Error processing trial expirations");
|
_logger.LogError(ex, "Error processing trial expirations");
|
||||||
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); // Wait 5 minutes on error
|
|
||||||
|
// Verificar cancelamento antes de fazer delay de erro
|
||||||
|
if (stoppingToken.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); // Wait 5 minutes on error
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// Cancelamento durante delay de erro - também é normal
|
||||||
|
_logger.LogInformation("TrialExpirationService cancelled during error delay");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("TrialExpirationService stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessTrialExpirationsAsync()
|
private async Task ProcessTrialExpirationsAsync()
|
||||||
{
|
{
|
||||||
using var scope = _serviceProvider.CreateScope();
|
try
|
||||||
var subscriptionRepository = scope.ServiceProvider.GetRequiredService<ISubscriptionRepository>();
|
|
||||||
var userPageRepository = scope.ServiceProvider.GetRequiredService<IUserPageRepository>();
|
|
||||||
var userRepository = scope.ServiceProvider.GetRequiredService<IUserRepository>();
|
|
||||||
|
|
||||||
_logger.LogInformation("Checking for expired trials...");
|
|
||||||
|
|
||||||
// Get all active trial subscriptions
|
|
||||||
var trialSubscriptions = await subscriptionRepository.GetTrialSubscriptionsAsync();
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
foreach (var subscription in trialSubscriptions)
|
|
||||||
{
|
{
|
||||||
try
|
using var scope = _serviceProvider.CreateScope();
|
||||||
|
var subscriptionRepository = scope.ServiceProvider.GetRequiredService<ISubscriptionRepository>();
|
||||||
|
var userPageRepository = scope.ServiceProvider.GetRequiredService<IUserPageRepository>();
|
||||||
|
var userRepository = scope.ServiceProvider.GetRequiredService<IUserRepository>();
|
||||||
|
|
||||||
|
_logger.LogInformation("Checking for expired trials...");
|
||||||
|
|
||||||
|
// Get all active trial subscriptions
|
||||||
|
var trialSubscriptions = await subscriptionRepository.GetTrialSubscriptionsAsync();
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
_logger.LogInformation($"Found {trialSubscriptions.Count} trial subscriptions to process");
|
||||||
|
|
||||||
|
foreach (var subscription in trialSubscriptions)
|
||||||
{
|
{
|
||||||
var user = await userRepository.GetByIdAsync(subscription.UserId);
|
try
|
||||||
if (user == null) continue;
|
|
||||||
|
|
||||||
var daysUntilExpiration = (subscription.CurrentPeriodEnd - now).TotalDays;
|
|
||||||
|
|
||||||
if (daysUntilExpiration <= 0)
|
|
||||||
{
|
{
|
||||||
// Trial expired - deactivate page
|
var user = await userRepository.GetByIdAsync(subscription.UserId);
|
||||||
_logger.LogInformation($"Trial expired for user {user.Email}");
|
if (user == null)
|
||||||
await HandleTrialExpiredAsync(user, subscription, userPageRepository);
|
{
|
||||||
|
_logger.LogWarning($"User not found for subscription {subscription.Id}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var daysUntilExpiration = (subscription.CurrentPeriodEnd - now).TotalDays;
|
||||||
|
|
||||||
|
if (daysUntilExpiration <= 0)
|
||||||
|
{
|
||||||
|
// Trial expired - deactivate page
|
||||||
|
_logger.LogInformation($"Trial expired for user {user.Email}");
|
||||||
|
await HandleTrialExpiredAsync(user, subscription, userPageRepository);
|
||||||
|
}
|
||||||
|
else if (daysUntilExpiration <= 2 && !user.NotifiedOfExpiration)
|
||||||
|
{
|
||||||
|
// Trial expiring soon - send notification
|
||||||
|
_logger.LogInformation($"Trial expiring in {daysUntilExpiration:F1} days for user {user.Email}");
|
||||||
|
await SendExpirationWarningAsync(user, subscription, daysUntilExpiration);
|
||||||
|
|
||||||
|
// Mark as notified
|
||||||
|
user.NotifiedOfExpiration = true;
|
||||||
|
await userRepository.UpdateAsync(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (daysUntilExpiration <= 2 && !user.NotifiedOfExpiration)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Trial expiring soon - send notification
|
_logger.LogError(ex, $"Error processing trial for subscription {subscription.Id}");
|
||||||
_logger.LogInformation($"Trial expiring in {daysUntilExpiration:F1} days for user {user.Email}");
|
|
||||||
await SendExpirationWarningAsync(user, subscription, daysUntilExpiration);
|
|
||||||
|
|
||||||
// Mark as notified
|
|
||||||
user.NotifiedOfExpiration = true;
|
|
||||||
await userRepository.UpdateAsync(user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
_logger.LogInformation("Finished checking trial expirations");
|
||||||
_logger.LogError(ex, $"Error processing trial for subscription {subscription.Id}");
|
}
|
||||||
}
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Critical error in ProcessTrialExpirationsAsync");
|
||||||
|
throw; // Re-throw para ser tratado pelo ExecuteAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Finished checking trial expirations");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleTrialExpiredAsync(
|
private async Task HandleTrialExpiredAsync(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user