BCards/src/BCards.Web/Controllers/AdminController.cs
2025-07-14 23:21:25 -03:00

961 lines
36 KiB
C#

using BCards.Web.Models;
using BCards.Web.Services;
using BCards.Web.Utils;
using BCards.Web.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace BCards.Web.Controllers;
[Authorize]
[Route("Admin")]
public class AdminController : Controller
{
private readonly IAuthService _authService;
private readonly IUserPageService _userPageService;
private readonly ICategoryService _categoryService;
private readonly IThemeService _themeService;
private readonly IModerationService _moderationService;
private readonly IEmailService _emailService;
private readonly ILivePageService _livePageService;
private readonly ILogger<AdminController> _logger;
public AdminController(
IAuthService authService,
IUserPageService userPageService,
ICategoryService categoryService,
IThemeService themeService,
IModerationService moderationService,
IEmailService emailService,
ILivePageService livePageService,
ILogger<AdminController> logger)
{
_authService = authService;
_userPageService = userPageService;
_categoryService = categoryService;
_themeService = themeService;
_moderationService = moderationService;
_emailService = emailService;
_livePageService = livePageService;
_logger = logger;
}
[HttpGet]
[Route("Dashboard")]
public async Task<IActionResult> Dashboard()
{
ViewBag.IsHomePage = false; // Menu normal do dashboard
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
var userPlanType = Enum.TryParse<PlanType>(user.CurrentPlan, true, out var planType) ? planType : PlanType.Trial;
var userPages = await _userPageService.GetUserPagesAsync(user.Id);
var dashboardModel = new DashboardViewModel
{
CurrentUser = user,
UserPages = userPages.Select(p => new UserPageSummary
{
Id = p.Id,
DisplayName = p.DisplayName,
Slug = p.Slug,
Category = p.Category,
Status = p.Status,
TotalClicks = p.Analytics?.TotalClicks ?? 0,
TotalViews = p.Analytics?.TotalViews ?? 0,
PreviewToken = p.PreviewToken,
CreatedAt = p.CreatedAt,
LastModerationStatus = p.ModerationHistory == null || p.ModerationHistory.Count == 0 || p.ModerationHistory.Last().Status == "rejected"
? null
: Enum.Parse<PageStatus>(p.ModerationHistory.Last().Status, true),
Motive = p.ModerationHistory == null || p.ModerationHistory.Count == 0 || p.ModerationHistory.Last().Status != "rejected"
? ""
: p.ModerationHistory.Last().Reason
}).ToList(),
CurrentPlan = new PlanInfo
{
Type = userPlanType,
Name = userPlanType.GetDisplayName(),
MaxPages = userPlanType.GetMaxPages(),
MaxLinksPerPage = userPlanType.GetMaxLinksPerPage(),
DurationDays = userPlanType.GetTrialDays(),
Price = userPlanType.GetPrice(),
AllowsAnalytics = userPlanType.AllowsAnalytics(),
AllowsCustomThemes = userPlanType.AllowsCustomThemes()
},
CanCreateNewPage = userPages.Count < userPlanType.GetMaxPages(),
DaysRemaining = userPlanType == PlanType.Trial ? CalculateTrialDaysRemaining(user) : 0
};
return View(dashboardModel);
}
private int CalculateTrialDaysRemaining(User user)
{
// This would be calculated based on subscription data
// For now, return a default value
return 7;
}
[HttpGet]
[Route("ManagePage")]
public async Task<IActionResult> ManagePage(string id = null)
{
ViewBag.IsHomePage = false;
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
var userPlanType = Enum.TryParse<PlanType>(user.CurrentPlan, true, out var planType) ? planType : PlanType.Trial;
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
if (string.IsNullOrEmpty(id) || id == "new")
{
// Check if user can create new page
var existingPages = await _userPageService.GetUserPagesAsync(user.Id);
var maxPages = userPlanType.GetMaxPages();
if (existingPages.Count >= maxPages)
{
TempData["Error"] = $"Você já atingiu o limite de {maxPages} página(s) do seu plano atual. Faça upgrade para criar mais páginas.";
return RedirectToAction("Dashboard");
}
// CRIAR NOVA PÁGINA
var model = new ManagePageViewModel
{
IsNewPage = true,
AvailableCategories = categories,
AvailableThemes = themes.Where(t => !t.IsPremium || userPlanType.AllowsCustomThemes()).ToList(),
MaxLinksAllowed = userPlanType.GetMaxLinksPerPage()
};
return View(model);
}
else
{
// EDITAR PÁGINA EXISTENTE
var page = await _userPageService.GetPageByIdAsync(id);
if (page == null || page.UserId != user.Id)
return NotFound();
var model = MapToManageViewModel(page, categories, themes, userPlanType);
return View(model);
}
}
[HttpPost]
[Route("ManagePage")]
public async Task<IActionResult> ManagePage(ManagePageViewModel model)
{
ViewBag.IsHomePage = false;
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
_logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}");
if (!ModelState.IsValid)
{
_logger.LogWarning("ModelState is invalid:");
foreach (var error in ModelState)
{
_logger.LogWarning($"Key: {error.Key}, Errors: {string.Join(", ", error.Value.Errors.Select(e => e.ErrorMessage))}");
}
// Repopulate dropdowns
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
return View(model);
}
if (model.IsNewPage)
{
// Generate slug if not provided
if (string.IsNullOrEmpty(model.Slug))
{
model.Slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName);
}
// Check if slug is available
if (!await _userPageService.ValidateSlugAsync(model.Category, model.Slug))
{
ModelState.AddModelError("Slug", "Esta URL já está em uso. Tente outra.");
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
return View(model);
}
// Check if user can create the requested number of links
var activeLinksCount = model.Links?.Count ?? 0;
if (activeLinksCount > model.MaxLinksAllowed)
{
ModelState.AddModelError("", $"Você excedeu o limite de {model.MaxLinksAllowed} links do seu plano atual.");
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
return View(model);
}
try
{
// Create new page
var userPage = await MapToUserPage(model, user.Id);
_logger.LogInformation($"Mapped to UserPage: {userPage.DisplayName}, Category: {userPage.Category}, Slug: {userPage.Slug}");
// Set status to Creating for new pages
userPage.Status = ViewModels.PageStatus.Creating;
await _userPageService.CreatePageAsync(userPage);
_logger.LogInformation("Page created successfully!");
// Generate preview token for development
var previewToken = await _moderationService.GeneratePreviewTokenAsync(userPage.Id);
var previewUrl = $"{Request.Scheme}://{Request.Host}/page/{userPage.Category}/{userPage.Slug}?preview={previewToken}";
userPage.PreviewToken = previewToken;
userPage.PreviewTokenExpiry = DateTime.UtcNow.AddHours(4);
await _userPageService.UpdatePageAsync(userPage);
TempData["Success"] = "Página criada com sucesso! Use o botão 'Enviar para Moderação' quando estiver pronta.";
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating page");
ModelState.AddModelError("", "Erro ao criar página. Tente novamente.");
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
TempData["Error"] = $"Erro ao criar página. Tente novamente. TechMsg: {ex.Message}";
return View(model);
}
}
else
{
// Update existing page
var existingPage = await _userPageService.GetPageByIdAsync(model.Id);
if (existingPage == null || existingPage.UserId != user.Id)
return NotFound();
// Check if user can create pages (for users with rejected pages)
var canCreatePage = await _moderationService.CanUserCreatePageAsync(user.Id);
if (!canCreatePage)
{
TempData["Error"] = "Você não pode editar páginas devido a muitas rejeições. Entre em contato com o suporte.";
return RedirectToAction("Dashboard");
}
UpdateUserPageFromModel(existingPage, model);
// Set status to PendingModeration for updates
existingPage.Status = ViewModels.PageStatus.Creating;
existingPage.ModerationAttempts = existingPage.ModerationAttempts;
await _userPageService.UpdatePageAsync(existingPage);
// Generate new preview token
var previewToken = await _moderationService.GeneratePreviewTokenAsync(existingPage.Id);
var previewUrl = $"{Request.Scheme}://{Request.Host}/page/{existingPage.Category}/{existingPage.Slug}?preview={previewToken}";
// Send email to user
await _emailService.SendModerationStatusAsync(
user.Email,
user.Name,
existingPage.DisplayName,
"pending",
null,
previewUrl);
TempData["Success"] = "Página atualizada e enviada para moderação!";
}
return RedirectToAction("Dashboard");
}
[HttpPost]
[Route("CreatePage")]
public async Task<IActionResult> CreatePage(CreatePageViewModel model)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
// Check if user already has a page
var existingPage = await _userPageService.GetUserPageAsync(user.Id);
if (existingPage != null)
return RedirectToAction("EditPage");
if (!ModelState.IsValid)
{
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
// Generate slug if not provided
if (string.IsNullOrEmpty(model.Slug))
{
model.Slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName);
}
// Check if slug is available
if (!await _userPageService.ValidateSlugAsync(model.Category, model.Slug))
{
ModelState.AddModelError("Slug", "Esta URL já está em uso. Tente outra.");
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
// Check if user can create the requested number of links
var activeLinksCount = model.Links?.Count ?? 0;
if (!await _userPageService.CanCreateLinksAsync(user.Id, activeLinksCount))
{
ModelState.AddModelError("", "Você excedeu o limite de links do seu plano atual.");
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
// Convert ViewModel to UserPage
var userPage = new UserPage
{
UserId = user.Id,
DisplayName = model.DisplayName,
Category = model.Category,
BusinessType = model.BusinessType,
Bio = model.Bio,
Slug = model.Slug,
Theme = await _themeService.GetThemeByNameAsync(model.SelectedTheme) ?? _themeService.GetDefaultTheme(),
Links = model.Links?.Select(l => new LinkItem
{
Title = l.Title,
Url = l.Url,
Description = l.Description,
Icon = l.Icon,
IsActive = true,
Order = model.Links.IndexOf(l)
}).ToList() ?? new List<LinkItem>()
};
// Add social media links
var socialLinks = new List<LinkItem>();
if (!string.IsNullOrEmpty(model.WhatsAppNumber))
{
socialLinks.Add(new LinkItem
{
Title = "WhatsApp",
Url = $"https://wa.me/{model.WhatsAppNumber.Replace("+", "").Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "")}",
Icon = "fab fa-whatsapp",
IsActive = true,
Order = userPage.Links.Count + socialLinks.Count
});
}
if (!string.IsNullOrEmpty(model.FacebookUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Facebook",
Url = model.FacebookUrl,
Icon = "fab fa-facebook",
IsActive = true,
Order = userPage.Links.Count + socialLinks.Count
});
}
if (!string.IsNullOrEmpty(model.TwitterUrl))
{
socialLinks.Add(new LinkItem
{
Title = "X / Twitter",
Url = model.TwitterUrl,
Icon = "fab fa-x-twitter",
IsActive = true,
Order = userPage.Links.Count + socialLinks.Count
});
}
if (!string.IsNullOrEmpty(model.InstagramUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Instagram",
Url = model.InstagramUrl,
Icon = "fab fa-instagram",
IsActive = true,
Order = userPage.Links.Count + socialLinks.Count
});
}
userPage.Links.AddRange(socialLinks);
await _userPageService.CreatePageAsync(userPage);
TempData["Success"] = "Página criada com sucesso!";
return RedirectToAction("Dashboard");
}
[HttpGet]
[Route("EditPage")]
public async Task<IActionResult> EditPage()
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
var userPage = await _userPageService.GetUserPageAsync(user.Id);
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
ViewBag.IsNew = userPage == null;
return View(userPage ?? new UserPage { UserId = user.Id });
}
[HttpPost]
[Route("EditPage")]
public async Task<IActionResult> EditPage(UserPage model)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
if (!ModelState.IsValid)
{
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
// Check if user can create the requested number of links
var activeLinksCount = model.Links?.Count(l => l.IsActive) ?? 0;
if (!await _userPageService.CanCreateLinksAsync(user.Id, activeLinksCount))
{
ModelState.AddModelError("", "Você excedeu o limite de links do seu plano atual.");
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
model.UserId = user.Id;
// Check if slug is available
if (!await _userPageService.ValidateSlugAsync(model.Category, model.Slug, model.Id))
{
ModelState.AddModelError("Slug", "Esta URL já está em uso. Tente outra.");
var categories = await _categoryService.GetAllCategoriesAsync();
var themes = await _themeService.GetAvailableThemesAsync();
ViewBag.Categories = categories;
ViewBag.Themes = themes;
return View(model);
}
if (string.IsNullOrEmpty(model.Id))
{
await _userPageService.CreatePageAsync(model);
}
else
{
await _userPageService.UpdatePageAsync(model);
}
TempData["Success"] = "Página salva com sucesso!";
return RedirectToAction("Dashboard");
}
[HttpPost]
[Route("CheckSlugAvailability")]
public async Task<IActionResult> CheckSlugAvailability(string category, string slug, string? excludeId = null)
{
if (string.IsNullOrWhiteSpace(category) || string.IsNullOrWhiteSpace(slug))
return Json(new { available = false, message = "Categoria e slug são obrigatórios." });
var isValid = await _userPageService.ValidateSlugAsync(category, slug, excludeId);
return Json(new { available = isValid, message = isValid ? "URL disponível!" : "Esta URL já está em uso." });
}
[HttpPost]
[Route("GenerateSlug")]
public async Task<IActionResult> GenerateSlug(string category, string name)
{
if (string.IsNullOrWhiteSpace(category) || string.IsNullOrWhiteSpace(name))
return Json(new { slug = "", category = "" });
var slug = await _userPageService.GenerateSlugAsync(category, name);
var categorySlug = SlugHelper.CreateCategorySlug(category).ToLower();
return Json(new { slug = slug, category = categorySlug });
}
[HttpGet]
[Route("Analytics")]
public async Task<IActionResult> Analytics()
{
ViewBag.IsHomePage = false;
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
var userPage = await _userPageService.GetUserPageAsync(user.Id);
if (userPage == null || !userPage.PlanLimitations.AllowAnalytics)
return RedirectToAction("Dashboard");
return View(userPage);
}
[HttpPost]
[Route("DeletePage/{id}")]
public async Task<IActionResult> DeletePage(string id)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
var userPage = await _userPageService.GetPageByIdAsync(id);
if (userPage == null || userPage.UserId != user.Id)
{
TempData["Error"] = "Página não encontrada!";
return RedirectToAction("Dashboard");
}
await _userPageService.DeletePageAsync(userPage.Id);
TempData["Success"] = "Página excluída com sucesso!";
return RedirectToAction("Dashboard");
}
private ManagePageViewModel MapToManageViewModel(UserPage page, List<Category> categories, List<PageTheme> themes, PlanType userPlanType)
{
return new ManagePageViewModel
{
Id = page.Id,
IsNewPage = false,
DisplayName = page.DisplayName,
Category = page.Category,
BusinessType = page.BusinessType,
Bio = page.Bio,
Slug = page.Slug,
SelectedTheme = page.Theme?.Name ?? "minimalist",
Links = page.Links?.Select((l, index) => new ManageLinkViewModel
{
Id = $"link_{index}",
Title = l.Title,
Url = l.Url,
Description = l.Description,
Icon = l.Icon,
Order = l.Order,
IsActive = l.IsActive,
Type = l.Type,
ProductTitle = l.ProductTitle,
ProductImage = l.ProductImage,
ProductPrice = l.ProductPrice,
ProductDescription = l.ProductDescription,
ProductDataCachedAt = l.ProductDataCachedAt
}).ToList() ?? new List<ManageLinkViewModel>(),
AvailableCategories = categories,
AvailableThemes = themes.Where(t => !t.IsPremium || userPlanType.AllowsCustomThemes()).ToList(),
MaxLinksAllowed = userPlanType.GetMaxLinksPerPage()
};
}
private async Task<UserPage> MapToUserPage(ManagePageViewModel model, string userId)
{
var theme = await _themeService.GetThemeByNameAsync(model.SelectedTheme) ?? _themeService.GetDefaultTheme();
var userPage = new UserPage
{
UserId = userId,
DisplayName = model.DisplayName,
Category = SlugHelper.ConvertCategory(model.Category.ToLower()),
BusinessType = model.BusinessType,
Bio = model.Bio,
Slug = SlugHelper.CreateSlug(model.Slug.ToLower()),
Theme = theme,
Status = ViewModels.PageStatus.Active,
Links = new List<LinkItem>()
};
// Add regular links
if (model.Links?.Any() == true)
{
userPage.Links.AddRange(model.Links.Where(l => !string.IsNullOrEmpty(l.Title) && !string.IsNullOrEmpty(l.Url))
.Select((l, index) => new LinkItem
{
Title = l.Title,
Url = l.Url.ToLower(),
Description = l.Description,
Icon = l.Icon,
IsActive = l.IsActive,
Order = index,
Type = l.Type,
ProductTitle = l.ProductTitle,
ProductImage = l.ProductImage,
ProductPrice = l.ProductPrice,
ProductDescription = l.ProductDescription,
ProductDataCachedAt = l.ProductDataCachedAt
}));
}
// Add social media links
var socialLinks = new List<LinkItem>();
var currentOrder = userPage.Links.Count;
if (!string.IsNullOrEmpty(model.WhatsAppNumber))
{
socialLinks.Add(new LinkItem
{
Title = "WhatsApp",
Url = $"https://wa.me/{model.WhatsAppNumber.Replace("+", "").Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "")}",
Icon = "fab fa-whatsapp",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.FacebookUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Facebook",
Url = model.FacebookUrl,
Icon = "fab fa-facebook",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.TwitterUrl))
{
socialLinks.Add(new LinkItem
{
Title = "X / Twitter",
Url = model.TwitterUrl,
Icon = "fab fa-x-twitter",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.InstagramUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Instagram",
Url = model.InstagramUrl,
Icon = "fab fa-instagram",
IsActive = true,
Order = currentOrder++
});
}
userPage.Links.AddRange(socialLinks);
return userPage;
}
private void UpdateUserPageFromModel(UserPage page, ManagePageViewModel model)
{
page.DisplayName = model.DisplayName;
page.Category = model.Category;
page.BusinessType = model.BusinessType;
page.Bio = model.Bio;
page.Slug = model.Slug;
page.UpdatedAt = DateTime.UtcNow;
// Update links
page.Links = new List<LinkItem>();
// Add regular links
if (model.Links?.Any() == true)
{
page.Links.AddRange(model.Links.Where(l => !string.IsNullOrEmpty(l.Title) && !string.IsNullOrEmpty(l.Url))
.Select((l, index) => new LinkItem
{
Title = l.Title,
Url = l.Url,
Description = l.Description,
Icon = l.Icon,
IsActive = l.IsActive,
Order = index,
Type = l.Type,
ProductTitle = l.ProductTitle,
ProductImage = l.ProductImage,
ProductPrice = l.ProductPrice,
ProductDescription = l.ProductDescription,
ProductDataCachedAt = l.ProductDataCachedAt
}));
}
// Add social media links (same logic as create)
var socialLinks = new List<LinkItem>();
var currentOrder = page.Links.Count;
if (!string.IsNullOrEmpty(model.WhatsAppNumber))
{
socialLinks.Add(new LinkItem
{
Title = "WhatsApp",
Url = $"https://wa.me/{model.WhatsAppNumber.Replace("+", "").Replace(" ", "").Replace("-", "").Replace("(", "").Replace(")", "")}",
Icon = "fab fa-whatsapp",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.FacebookUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Facebook",
Url = model.FacebookUrl,
Icon = "fab fa-facebook",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.TwitterUrl))
{
socialLinks.Add(new LinkItem
{
Title = "X / Twitter",
Url = model.TwitterUrl,
Icon = "fab fa-x-twitter",
IsActive = true,
Order = currentOrder++
});
}
if (!string.IsNullOrEmpty(model.InstagramUrl))
{
socialLinks.Add(new LinkItem
{
Title = "Instagram",
Url = model.InstagramUrl,
Icon = "fab fa-instagram",
IsActive = true,
Order = currentOrder++
});
}
page.Links.AddRange(socialLinks);
}
[HttpPost]
[Route("SubmitForModeration/{id}")]
public async Task<IActionResult> SubmitForModeration(string id)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return Json(new { success = false, message = "Usuário não autenticado" });
var pageItem = await _userPageService.GetPageByIdAsync(id);
if (pageItem == null || pageItem.UserId != user.Id)
return Json(new { success = false, message = "Página não encontrada" });
// Validar status atual
if (pageItem.Status != ViewModels.PageStatus.Creating && pageItem.Status != ViewModels.PageStatus.Rejected)
return Json(new { success = false, message = "Página não pode ser enviada para moderação neste momento" });
// Validar se tem pelo menos 1 link ativo
var activeLinksCount = pageItem.Links?.Count(l => l.IsActive) ?? 0;
if (activeLinksCount < 1)
return Json(new { success = false, message = "Página deve ter pelo menos 1 link ativo para ser enviada" });
try
{
// Mudar status para PendingModeration
pageItem.Status = ViewModels.PageStatus.PendingModeration;
pageItem.ModerationAttempts++;
pageItem.UpdatedAt = DateTime.UtcNow;
await _userPageService.UpdatePageAsync(pageItem);
// Enviar email de notificação ao usuário
await _emailService.SendModerationStatusAsync(
user.Email,
user.Name,
pageItem.DisplayName,
"pending",
null,
$"{Request.Scheme}://{Request.Host}/page/{pageItem.Category}/{pageItem.Slug}?preview={pageItem.PreviewToken}");
_logger.LogInformation($"Page {pageItem.Id} submitted for moderation by user {user.Id}");
return Json(new {
success = true,
message = "Página enviada para moderação com sucesso! Você receberá um email quando for processada.",
newStatus = "PendingModeration"
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error submitting page {id} for moderation");
return Json(new { success = false, message = "Erro interno. Tente novamente." });
}
}
[HttpPost]
[Route("RefreshPreviewToken/{id}")]
public async Task<IActionResult> RefreshPreviewToken(string id)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return Json(new { success = false, message = "Não autorizado" });
var pageItem = await _userPageService.GetPageByIdAsync(id);
if (pageItem == null || pageItem.UserId != user.Id)
return Json(new { success = false, message = "Página não encontrada" });
// Só renovar token para páginas "Creating"
if (pageItem.Status != ViewModels.PageStatus.Creating)
return Json(new { success = false, message = "Token só pode ser renovado para páginas em desenvolvimento" });
try
{
// Gerar novo token com 4 horas de validade
var newToken = await _moderationService.GeneratePreviewTokenAsync(pageItem.Id);
var previewUrl = $"{Request.Scheme}://{Request.Host}/page/{pageItem.Category}/{pageItem.Slug}?preview={newToken}";
return Json(new {
success = true,
previewToken = newToken,
previewUrl = previewUrl,
expiresAt = DateTime.UtcNow.AddHours(4).ToString("yyyy-MM-dd HH:mm:ss")
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error refreshing preview token for page {id}");
return Json(new { success = false, message = "Erro ao renovar token" });
}
}
[HttpPost]
[Route("GeneratePreviewToken/{id}")]
public async Task<IActionResult> GeneratePreviewToken(string id)
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return Json(new { success = false, message = "Usuário não autenticado" });
var pageItem = await _userPageService.GetPageByIdAsync(id);
if (pageItem == null || pageItem.UserId != user.Id)
return Json(new { success = false, message = "Página não encontrada" });
// Verificar se página pode ter preview
if (pageItem.Status != ViewModels.PageStatus.Creating &&
pageItem.Status != ViewModels.PageStatus.PendingModeration &&
pageItem.Status != ViewModels.PageStatus.Rejected)
{
return Json(new { success = false, message = "Preview não disponível para este status" });
}
try
{
// Gerar novo token com 4 horas de validade
var newToken = await _moderationService.GeneratePreviewTokenAsync(pageItem.Id);
_logger.LogInformation($"Preview token generated for page {pageItem.Id} by user {user.Id}");
return Json(new {
success = true,
previewToken = newToken,
message = "Preview gerado com sucesso!",
expiresAt = DateTime.UtcNow.AddHours(4).ToString("yyyy-MM-dd HH:mm:ss")
});
}
catch (Exception ex)
{
_logger.LogError(ex, $"Error generating preview token for page {id}");
return Json(new { success = false, message = "Erro interno. Tente novamente." });
}
}
[HttpPost]
[Route("MigrateToLivePages")]
public async Task<IActionResult> MigrateToLivePages()
{
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return Json(new { success = false, message = "Usuário não autenticado" });
try
{
// Buscar todas as páginas ativas do usuário atual
var activePages = await _userPageService.GetUserPagesAsync(user.Id);
var eligiblePages = activePages.Where(p => p.Status == ViewModels.PageStatus.Active).ToList();
if (!eligiblePages.Any())
{
return Json(new {
success = false,
message = "Nenhuma página ativa encontrada para migração"
});
}
int successCount = 0;
int errorCount = 0;
var errors = new List<string>();
foreach (var page in eligiblePages)
{
try
{
await _livePageService.SyncFromUserPageAsync(page.Id);
successCount++;
_logger.LogInformation($"Successfully migrated page {page.Id} ({page.DisplayName}) to LivePages");
}
catch (Exception ex)
{
errorCount++;
var errorMsg = $"Erro ao migrar '{page.DisplayName}': {ex.Message}";
errors.Add(errorMsg);
_logger.LogError(ex, $"Failed to migrate page {page.Id} to LivePages");
}
}
var message = $"Migração concluída: {successCount} páginas migradas com sucesso";
if (errorCount > 0)
{
message += $", {errorCount} erros encontrados";
}
return Json(new {
success = errorCount == 0,
message = message,
details = new {
totalPages = eligiblePages.Count,
successCount = successCount,
errorCount = errorCount,
errors = errors
}
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during LivePages migration");
return Json(new {
success = false,
message = $"Erro durante migração: {ex.Message}"
});
}
}
}