fix: logar erro
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 16m11s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 2m23s
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:
Ricardo Carneiro 2025-09-14 01:05:51 -03:00
parent f98dac9178
commit 4bad39ec85

View File

@ -138,49 +138,59 @@ public class AdminController : Controller
[Route("ManagePage")] [Route("ManagePage")]
public async Task<IActionResult> ManagePage(string id = null) public async Task<IActionResult> ManagePage(string id = null)
{ {
ViewBag.IsHomePage = false; try
{
ViewBag.IsHomePage = false;
var user = await _authService.GetCurrentUserAsync(User); var user = await _authService.GetCurrentUserAsync(User);
if (user == null) if (user == null)
return RedirectToAction("Login", "Auth"); 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") var userPlanType = Enum.TryParse<PlanType>(user.CurrentPlan, true, out var planType) ? planType : PlanType.Trial;
{ var categories = await _categoryService.GetAllCategoriesAsync();
// Check if user can create new page var themes = await _themeService.GetAvailableThemesAsync();
var existingPages = await _userPageService.GetUserPagesAsync(user.Id);
var maxPages = userPlanType.GetMaxPages(); 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) 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."; 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"); return RedirectToAction("Dashboard");
}
// CRIAR NOVA PÁGINA
var planLimitations = await _paymentService.GetPlanLimitationsAsync(userPlanType.ToString());
var model = new ManagePageViewModel
{
IsNewPage = true,
AvailableCategories = categories,
AvailableThemes = themes.Where(t => !t.IsPremium || userPlanType.AllowsCustomThemes()).ToList(),
MaxLinksAllowed = userPlanType.GetMaxLinksPerPage(),
AllowProductLinks = planLimitations.AllowProductLinks
};
return View(model);
} }
else
// CRIAR NOVA PÁGINA
var planLimitations = await _paymentService.GetPlanLimitationsAsync(userPlanType.ToString());
var model = new ManagePageViewModel
{ {
IsNewPage = true, // EDITAR PÁGINA EXISTENTE
AvailableCategories = categories, var page = await _userPageService.GetPageByIdAsync(id);
AvailableThemes = themes.Where(t => !t.IsPremium || userPlanType.AllowsCustomThemes()).ToList(), if (page == null || page.UserId != user.Id)
MaxLinksAllowed = userPlanType.GetMaxLinksPerPage(), return NotFound();
AllowProductLinks = planLimitations.AllowProductLinks
};
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 = await MapToManageViewModel(page, categories, themes, userPlanType); var model = await MapToManageViewModel(page, categories, themes, userPlanType);
return View(model); return View(model);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ManagePage GET");
TempData["Error"] = "Ocorreu um erro ao carregar a página. Tente novamente.";
throw new Exception("Erro ao salvar o bcard", ex);
} }
} }
@ -190,197 +200,210 @@ public class AdminController : Controller
[RequestFormLimits(MultipartBodyLengthLimit = 5 * 1024 * 1024)] [RequestFormLimits(MultipartBodyLengthLimit = 5 * 1024 * 1024)]
public async Task<IActionResult> ManagePage(ManagePageViewModel model) public async Task<IActionResult> ManagePage(ManagePageViewModel model)
{ {
ViewBag.IsHomePage = false; string userId = "";
try
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
// Limpar campos de redes sociais que são apenas espaços (tratados como vazios)
CleanSocialMediaFields(model);
_logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}");
ModelState.Remove<ManagePageViewModel>(x => x.InstagramUrl);
ModelState.Remove<ManagePageViewModel>(x => x.FacebookUrl);
ModelState.Remove<ManagePageViewModel>(x => x.TwitterUrl);
ModelState.Remove<ManagePageViewModel>(x => x.WhatsAppNumber);
_logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}");
//Logar modelstate em information
_logger.LogInformation($"ModelState: {JsonSerializer.Serialize(ModelState)}");
// Processar upload de imagem se fornecida
if (model.ProfileImageFile != null && model.ProfileImageFile.Length > 0)
{ {
try
ViewBag.IsHomePage = false;
var user = await _authService.GetCurrentUserAsync(User);
if (user == null)
return RedirectToAction("Login", "Auth");
userId = user.Id;
// Limpar campos de redes sociais que são apenas espaços (tratados como vazios)
CleanSocialMediaFields(model);
_logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}");
ModelState.Remove<ManagePageViewModel>(x => x.InstagramUrl);
ModelState.Remove<ManagePageViewModel>(x => x.FacebookUrl);
ModelState.Remove<ManagePageViewModel>(x => x.TwitterUrl);
ModelState.Remove<ManagePageViewModel>(x => x.WhatsAppNumber);
_logger.LogInformation($"ManagePage POST: IsNewPage={model.IsNewPage}, DisplayName={model.DisplayName}, Category={model.Category}, Links={model.Links?.Count ?? 0}");
//Logar modelstate em information
_logger.LogInformation($"ModelState: {JsonSerializer.Serialize(ModelState)}");
// Processar upload de imagem se fornecida
if (model.ProfileImageFile != null && model.ProfileImageFile.Length > 0)
{ {
using var memoryStream = new MemoryStream(); try
await model.ProfileImageFile.CopyToAsync(memoryStream); {
var imageBytes = memoryStream.ToArray(); using var memoryStream = new MemoryStream();
await model.ProfileImageFile.CopyToAsync(memoryStream);
var imageBytes = memoryStream.ToArray();
var imageId = await _imageStorage.SaveImageAsync( var imageId = await _imageStorage.SaveImageAsync(
imageBytes, imageBytes,
model.ProfileImageFile.FileName, model.ProfileImageFile.FileName,
model.ProfileImageFile.ContentType model.ProfileImageFile.ContentType
); );
model.ProfileImageId = imageId; model.ProfileImageId = imageId;
_logger.LogInformation("Profile image uploaded successfully: {ImageId}", imageId); _logger.LogInformation("Profile image uploaded successfully: {ImageId}", imageId);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Userid: {userId} - Error uploading profile image");
ModelState.AddModelError("ProfileImageFile", "Erro ao fazer upload da imagem. Tente novamente.");
TempData["ImageError"] = "Erro ao processar a imagem. Verifique o formato e tamanho.";
// Preservar dados do form e repopular dropdowns
var userPlanType = Enum.TryParse<PlanType>(user.CurrentPlan, true, out var planType) ? planType : PlanType.Trial;
var planLimitations = await _paymentService.GetPlanLimitationsAsync(userPlanType.ToString());
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
model.MaxLinksAllowed = userPlanType.GetMaxLinksPerPage();
model.AllowProductLinks = planLimitations.AllowProductLinks;
// Preservar ProfileImageId existente se estava editando
if (!model.IsNewPage && !string.IsNullOrEmpty(model.Id))
{
var existingPage = await _userPageService.GetPageByIdAsync(model.Id);
if (existingPage != null)
{
model.ProfileImageId = existingPage.ProfileImageId;
}
}
return View(model);
}
} }
catch (Exception ex)
if (!ModelState.IsValid)
{ {
_logger.LogError(ex, "Error uploading profile image"); _logger.LogWarning("ModelState is invalid:");
ModelState.AddModelError("ProfileImageFile", "Erro ao fazer upload da imagem. Tente novamente."); foreach (var error in ModelState)
TempData["ImageError"] = "Erro ao processar a imagem. Verifique o formato e tamanho."; {
_logger.LogWarning($"Key: {error.Key}, Errors: {string.Join(", ", error.Value.Errors.Select(e => e.ErrorMessage))}");
// Preservar dados do form e repopular dropdowns }
var userPlanType = Enum.TryParse<PlanType>(user.CurrentPlan, true, out var planType) ? planType : PlanType.Trial;
var planLimitations = await _paymentService.GetPlanLimitationsAsync(userPlanType.ToString()); // Repopulate dropdowns
var slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName);
model.Slug = slug;
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync(); model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync(); model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
model.MaxLinksAllowed = userPlanType.GetMaxLinksPerPage(); return View(model);
model.AllowProductLinks = planLimitations.AllowProductLinks; }
// Preservar ProfileImageId existente se estava editando if (model.IsNewPage)
if (!model.IsNewPage && !string.IsNullOrEmpty(model.Id)) {
// Generate slug if not provided
if (string.IsNullOrEmpty(model.Slug))
{ {
var existingPage = await _userPageService.GetPageByIdAsync(model.Id); model.Slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName);
if (existingPage != null) }
// 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!");
// Token será gerado apenas quando usuário clicar "Testar Página"
TempData["Success"] = "Página criada com sucesso! Use o botão 'Enviar para Moderação' quando estiver pronta.";
}
catch (Exception ex)
{
_logger.LogError(ex, $"Userid: {userId} - 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");
}
// IMPORTANTE: Tratar remoção de imagem ou preservar existente se não houver novo upload
if (model.ProfileImageFile == null || model.ProfileImageFile.Length == 0)
{
if (model.ProfileImageId == "REMOVE_IMAGE")
{ {
// Usuário quer remover a imagem existente
model.ProfileImageId = null;
_logger.LogInformation("Profile image removed by user request");
}
else
{
// Preservar imagem existente
model.ProfileImageId = existingPage.ProfileImageId; model.ProfileImageId = existingPage.ProfileImageId;
} }
} }
return View(model);
}
}
if (!ModelState.IsValid) await UpdateUserPageFromModel(existingPage, model);
{
_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 // Set status to PendingModeration for updates
var slug = await _userPageService.GenerateSlugAsync(model.Category, model.DisplayName); existingPage.Status = ViewModels.PageStatus.Creating;
model.Slug = slug; existingPage.ModerationAttempts = existingPage.ModerationAttempts;
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync();
model.AvailableThemes = await _themeService.GetAvailableThemesAsync();
return View(model);
}
if (model.IsNewPage) await _userPageService.UpdatePageAsync(existingPage);
{
// 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!");
// Token será gerado apenas quando usuário clicar "Testar Página" // Token será gerado apenas quando usuário clicar "Testar Página"
TempData["Success"] = "Página criada com sucesso! Use o botão 'Enviar para Moderação' quando estiver pronta."; // Send email to user
} await _emailService.SendModerationStatusAsync(
catch (Exception ex) user.Email,
{ user.Name,
_logger.LogError(ex, "Error creating page"); existingPage.DisplayName,
ModelState.AddModelError("", "Erro ao criar página. Tente novamente."); "pending",
model.AvailableCategories = await _categoryService.GetAllCategoriesAsync(); null,
model.AvailableThemes = await _themeService.GetAvailableThemesAsync(); null); // previewUrl não é mais necessário - token será gerado no clique
TempData["Error"] = $"Erro ao criar página. Tente novamente. TechMsg: {ex.Message}";
return View(model); TempData["Success"] = "Página atualizada! Teste e envie para moderação.";
} }
return RedirectToAction("Dashboard");
} }
else catch (Exception ex)
{ {
// Update existing page _logger.LogError(ex, $"Userid: {userId} - Error in ManagePage GET");
var existingPage = await _userPageService.GetPageByIdAsync(model.Id); TempData["Error"] = "Ocorreu um erro ao carregar a página. Tente novamente.";
if (existingPage == null || existingPage.UserId != user.Id) throw new Exception("Erro ao salvar o bcard", ex);
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");
}
// IMPORTANTE: Tratar remoção de imagem ou preservar existente se não houver novo upload
if (model.ProfileImageFile == null || model.ProfileImageFile.Length == 0)
{
if (model.ProfileImageId == "REMOVE_IMAGE")
{
// Usuário quer remover a imagem existente
model.ProfileImageId = null;
_logger.LogInformation("Profile image removed by user request");
}
else
{
// Preservar imagem existente
model.ProfileImageId = existingPage.ProfileImageId;
}
}
await UpdateUserPageFromModel(existingPage, model);
// Set status to PendingModeration for updates
existingPage.Status = ViewModels.PageStatus.Creating;
existingPage.ModerationAttempts = existingPage.ModerationAttempts;
await _userPageService.UpdatePageAsync(existingPage);
// Token será gerado apenas quando usuário clicar "Testar Página"
// Send email to user
await _emailService.SendModerationStatusAsync(
user.Email,
user.Name,
existingPage.DisplayName,
"pending",
null,
null); // previewUrl não é mais necessário - token será gerado no clique
TempData["Success"] = "Página atualizada! Teste e envie para moderação.";
} }
return RedirectToAction("Dashboard");
} }
[HttpPost] [HttpPost]