fix: fluxo de paginas e preview
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 16m26s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 2m20s
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 16m26s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 2m20s
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
f28dc8daa8
commit
930ce8dab3
13
.dockerignore
Normal file
13
.dockerignore
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
README.md
|
||||||
|
tests/
|
||||||
|
docs/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
**/.DS_Store
|
||||||
|
**/Thumbs.db
|
||||||
|
|
||||||
@ -92,6 +92,16 @@ public class UserPage : IPageDisplay
|
|||||||
[BsonElement("previewViewCount")]
|
[BsonElement("previewViewCount")]
|
||||||
public int PreviewViewCount { get; set; } = 0;
|
public int PreviewViewCount { get; set; } = 0;
|
||||||
|
|
||||||
|
// Exclusão lógica
|
||||||
|
[BsonElement("deletedAt")]
|
||||||
|
public DateTime? DeletedAt { get; set; }
|
||||||
|
|
||||||
|
[BsonElement("deletionReason")]
|
||||||
|
public string? DeletionReason { get; set; } // "trial_expired", "user_requested", "moderation_violation"
|
||||||
|
|
||||||
|
[BsonIgnore]
|
||||||
|
public bool IsDeleted => DeletedAt.HasValue;
|
||||||
|
|
||||||
public string FullUrl => $"page/{Category}/{Slug}";
|
public string FullUrl => $"page/{Category}/{Slug}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -564,7 +564,6 @@ app.UseAuthorization();
|
|||||||
app.UseMiddleware<SmartCacheMiddleware>();
|
app.UseMiddleware<SmartCacheMiddleware>();
|
||||||
app.UseMiddleware<AuthCacheMiddleware>();
|
app.UseMiddleware<AuthCacheMiddleware>();
|
||||||
app.UseMiddleware<PlanLimitationMiddleware>();
|
app.UseMiddleware<PlanLimitationMiddleware>();
|
||||||
app.UseMiddleware<PreviewTokenMiddleware>();
|
|
||||||
app.UseMiddleware<PageStatusMiddleware>();
|
app.UseMiddleware<PageStatusMiddleware>();
|
||||||
app.UseMiddleware<ModerationAuthMiddleware>();
|
app.UseMiddleware<ModerationAuthMiddleware>();
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ public class ModerationService : IModerationService
|
|||||||
public async Task<string> GeneratePreviewTokenAsync(string pageId)
|
public async Task<string> GeneratePreviewTokenAsync(string pageId)
|
||||||
{
|
{
|
||||||
var token = Guid.NewGuid().ToString("N")[..16];
|
var token = Guid.NewGuid().ToString("N")[..16];
|
||||||
var expiry = DateTime.UtcNow.AddDays(30); // Token válido por 30 dias
|
var expiry = DateTime.UtcNow.AddHours(4); // Token válido por 4 horas
|
||||||
var page = await _userPageRepository.GetByIdAsync(pageId);
|
var page = await _userPageRepository.GetByIdAsync(pageId);
|
||||||
page.PreviewToken = token;
|
page.PreviewToken = token;
|
||||||
page.PreviewTokenExpiry = expiry;
|
page.PreviewTokenExpiry = expiry;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using BCards.Web.Models;
|
using BCards.Web.Models;
|
||||||
using BCards.Web.Repositories;
|
using BCards.Web.Repositories;
|
||||||
|
using BCards.Web.ViewModels;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
|
||||||
namespace BCards.Web.Services;
|
namespace BCards.Web.Services;
|
||||||
@ -75,7 +76,7 @@ public class TrialExpirationService : BackgroundService
|
|||||||
|
|
||||||
_logger.LogInformation("Checking for expired trials...");
|
_logger.LogInformation("Checking for expired trials...");
|
||||||
|
|
||||||
// Get all active trial subscriptions
|
// Process trial expirations
|
||||||
var trialSubscriptions = await subscriptionRepository.GetTrialSubscriptionsAsync();
|
var trialSubscriptions = await subscriptionRepository.GetTrialSubscriptionsAsync();
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
@ -118,6 +119,9 @@ public class TrialExpirationService : BackgroundService
|
|||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Finished checking trial expirations");
|
_logger.LogInformation("Finished checking trial expirations");
|
||||||
|
|
||||||
|
// Process permanent deletions (pages deleted for more than 30 days)
|
||||||
|
await ProcessPermanentDeletionsAsync(userPageRepository);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -127,15 +131,17 @@ public class TrialExpirationService : BackgroundService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleTrialExpiredAsync(
|
private async Task HandleTrialExpiredAsync(
|
||||||
User user,
|
User user,
|
||||||
Subscription subscription,
|
Subscription subscription,
|
||||||
IUserPageRepository userPageRepository)
|
IUserPageRepository userPageRepository)
|
||||||
{
|
{
|
||||||
// Deactivate user page
|
// Mark user page as expired (logical deletion)
|
||||||
var userPage = await userPageRepository.GetByUserIdAsync(user.Id);
|
var userPage = await userPageRepository.GetByUserIdAsync(user.Id);
|
||||||
if (userPage != null)
|
if (userPage != null)
|
||||||
{
|
{
|
||||||
userPage.IsActive = false;
|
userPage.Status = PageStatus.Expired;
|
||||||
|
userPage.DeletedAt = DateTime.UtcNow;
|
||||||
|
userPage.DeletionReason = "trial_expired";
|
||||||
userPage.UpdatedAt = DateTime.UtcNow;
|
userPage.UpdatedAt = DateTime.UtcNow;
|
||||||
await userPageRepository.UpdateAsync(userPage);
|
await userPageRepository.UpdateAsync(userPage);
|
||||||
}
|
}
|
||||||
@ -218,4 +224,48 @@ public class TrialExpirationService : BackgroundService
|
|||||||
// TODO: Get from configuration
|
// TODO: Get from configuration
|
||||||
return "https://bcards.com.br/pricing";
|
return "https://bcards.com.br/pricing";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ProcessPermanentDeletionsAsync(IUserPageRepository userPageRepository)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Checking for pages to permanently delete...");
|
||||||
|
|
||||||
|
// Find pages that have been logically deleted for more than 30 days
|
||||||
|
var cutoffDate = DateTime.UtcNow.AddDays(-30);
|
||||||
|
|
||||||
|
// Get all expired pages older than 30 days
|
||||||
|
var filter = MongoDB.Driver.Builders<UserPage>.Filter.And(
|
||||||
|
MongoDB.Driver.Builders<UserPage>.Filter.Eq(p => p.Status, PageStatus.Expired),
|
||||||
|
MongoDB.Driver.Builders<UserPage>.Filter.Ne(p => p.DeletedAt, null),
|
||||||
|
MongoDB.Driver.Builders<UserPage>.Filter.Lt(p => p.DeletedAt, cutoffDate)
|
||||||
|
);
|
||||||
|
|
||||||
|
var pagesToDelete = await userPageRepository.GetManyAsync(filter);
|
||||||
|
|
||||||
|
_logger.LogInformation($"Found {pagesToDelete.Count} pages to permanently delete");
|
||||||
|
|
||||||
|
foreach (var page in pagesToDelete)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Permanently deleting page {page.Id} ({page.DisplayName}) - deleted at {page.DeletedAt}");
|
||||||
|
await userPageRepository.DeleteAsync(page.Id);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, $"Error permanently deleting page {page.Id}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pagesToDelete.Count > 0)
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Permanently deleted {pagesToDelete.Count} pages");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Error processing permanent deletions");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -74,6 +74,9 @@
|
|||||||
case BCards.Web.ViewModels.PageStatus.Rejected:
|
case BCards.Web.ViewModels.PageStatus.Rejected:
|
||||||
<span class="badge bg-danger">Rejeitada</span>
|
<span class="badge bg-danger">Rejeitada</span>
|
||||||
break;
|
break;
|
||||||
|
case BCards.Web.ViewModels.PageStatus.Expired:
|
||||||
|
<span class="badge bg-warning"><i class="fas fa-clock me-1"></i>Trial Expirado</span>
|
||||||
|
break;
|
||||||
case BCards.Web.ViewModels.PageStatus.Creating:
|
case BCards.Web.ViewModels.PageStatus.Creating:
|
||||||
<span class="badge bg-info"><i class="fas fa-edit me-1"></i>Em Criação</span>
|
<span class="badge bg-info"><i class="fas fa-edit me-1"></i>Em Criação</span>
|
||||||
break;
|
break;
|
||||||
@ -83,6 +86,20 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@* Exibir histórico de rejeição se existir *@
|
||||||
|
@if (pageItem.Status == BCards.Web.ViewModels.PageStatus.Rejected && !string.IsNullOrEmpty(pageItem.Motive))
|
||||||
|
{
|
||||||
|
<div class="alert alert-danger alert-sm mb-3 p-2">
|
||||||
|
<div class="d-flex align-items-start">
|
||||||
|
<i class="fas fa-exclamation-triangle me-2 mt-1 flex-shrink-0"></i>
|
||||||
|
<div class="flex-grow-1 small">
|
||||||
|
<strong>Motivo da rejeição:</strong><br>
|
||||||
|
@pageItem.Motive
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if (Model.CurrentPlan.AllowsAnalytics)
|
@if (Model.CurrentPlan.AllowsAnalytics)
|
||||||
{
|
{
|
||||||
<div class="row text-center small mb-3">
|
<div class="row text-center small mb-3">
|
||||||
@ -129,6 +146,15 @@
|
|||||||
<i class="fas fa-hourglass-half me-1"></i>Aguardando Moderação
|
<i class="fas fa-hourglass-half me-1"></i>Aguardando Moderação
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
else if (pageItem.Status == BCards.Web.ViewModels.PageStatus.Expired)
|
||||||
|
{
|
||||||
|
<a href="@Url.Action("Pricing", "Home")" class="btn btn-warning">
|
||||||
|
<i class="fas fa-crown me-1"></i>Reativar Página
|
||||||
|
</a>
|
||||||
|
<small class="text-muted d-block mt-2">
|
||||||
|
<i class="fas fa-info-circle me-1"></i>Sua página foi pausada. Escolha um plano para reativá-la.
|
||||||
|
</small>
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<button class="btn btn-secondary" disabled>
|
<button class="btn btn-secondary" disabled>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user