id}"; Cache::put($cacheKey, $code, now()->addMinutes(10)); // Enviar email Mail::to($user->email)->send(new AccountDeletionConfirmation( $code, $user->name, $user->locale ?? $user->language ?? 'pt-BR' )); return response()->json([ 'success' => true, 'message' => 'Código de confirmação enviado para seu email', 'expires_at' => now()->addMinutes(10)->toISOString() ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Erro ao enviar código de confirmação', 'error' => $e->getMessage() ], 500); } } /** * Exportar backup completo dos dados do usuário */ public function exportBackup(Request $request) { try { $user = Auth::user(); // Coletar todos os dados do usuário (apenas relações existentes) $backup = [ 'version' => '1.0', 'exported_at' => now()->toISOString(), 'user' => [ 'name' => $user->name, 'email' => $user->email, 'locale' => $user->locale ?? $user->language ?? 'pt-BR', ], 'accounts' => $user->accounts()->get()->makeHidden(['user']), 'categories' => $user->categories()->get()->makeHidden(['user']), 'budgets' => $user->budgets()->get()->makeHidden(['user']), 'transactions' => $user->transactions()->get()->makeHidden(['user']), 'goals' => $user->goals()->get()->makeHidden(['user']), ]; // Gerar nome do arquivo $fileName = 'webmoney_backup_' . $user->id . '_' . now()->format('Y-m-d_His') . '.json'; // Salvar temporariamente $filePath = 'backups/' . $fileName; $jsonData = json_encode($backup, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); if ($jsonData === false) { throw new \Exception('Erro ao serializar dados: ' . json_last_error_msg()); } Storage::disk('local')->put($filePath, $jsonData); // Retornar URL para download return response()->json([ 'success' => true, 'message' => 'Backup criado com sucesso', 'download_url' => route('download.backup', ['file' => $fileName]), 'file_size' => Storage::disk('local')->size($filePath), 'expires_in' => '24 horas' ]); } catch (\Exception $e) { \Log::error('Export backup error', [ 'user_id' => Auth::id(), 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => 'Erro ao criar backup', 'error' => config('app.debug') ? $e->getMessage() : 'Erro interno' ], 500); } } /** * Download do arquivo de backup */ public function downloadBackup($file) { try { $filePath = 'backups/' . $file; if (!Storage::disk('local')->exists($filePath)) { abort(404, 'Arquivo não encontrado'); } return Storage::disk('local')->download($filePath); } catch (\Exception $e) { abort(500, 'Erro ao baixar backup'); } } /** * Validar código e executar hard delete */ public function executeHardDelete(Request $request) { $request->validate([ 'code' => 'required|string|size:6', 'confirmation_text' => 'required|string|in:DELETAR' ]); try { $user = Auth::user(); $cacheKey = "account_deletion_code_{$user->id}"; // Verificar código $storedCode = Cache::get($cacheKey); if (!$storedCode) { return response()->json([ 'success' => false, 'message' => 'Código expirado ou inválido' ], 400); } if ($storedCode !== $request->code) { return response()->json([ 'success' => false, 'message' => 'Código incorreto' ], 400); } // Limpar cache Cache::forget($cacheKey); // Executar hard delete em transação DB::beginTransaction(); try { // Deletar em ordem (respeitando foreign keys) // 1. Transações $user->transactions()->delete(); // 2. Orçamentos $user->budgets()->delete(); // 3. Histórico de preços de investimentos DB::table('investment_price_histories') ->whereIn('investment_id', $user->investments()->pluck('id')) ->delete(); // 4. Investimentos $user->investments()->delete(); // 5. Cartões de crédito $user->creditCards()->delete(); // 6. Contas de passivos $user->liabilityAccounts()->delete(); // 7. Contas de ativos $user->assetAccounts()->delete(); // 8. Contas bancárias $user->accounts()->delete(); // 9. Palavras-chave de centros de custo $costCenterIds = $user->costCenters()->pluck('id'); DB::table('cost_center_keywords')->whereIn('cost_center_id', $costCenterIds)->delete(); // 10. Centros de custo (não-sistema) $user->costCenters()->where('is_system', false)->delete(); // 11. Categorias customizadas $user->categories()->where('is_custom', true)->delete(); // 12. Objetivos $user->goals()->delete(); // 13. Tokens de autenticação $user->tokens()->delete(); // 14. Usuário $userName = $user->name; $userEmail = $user->email; $user->delete(); DB::commit(); return response()->json([ 'success' => true, 'message' => 'Conta deletada permanentemente', 'deleted_user' => [ 'name' => $userName, 'email' => $userEmail ] ]); } catch (\Exception $e) { DB::rollBack(); throw $e; } } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Erro ao executar exclusão', 'error' => $e->getMessage() ], 500); } } /** * Importar backup para conta atual */ public function importBackup(Request $request) { $request->validate([ 'backup_file' => 'required|file|mimes:json|max:51200' // Max 50MB ]); try { $user = Auth::user(); // Ler arquivo $content = file_get_contents($request->file('backup_file')->getRealPath()); $backup = json_decode($content, true); if (!$backup || !isset($backup['version'])) { return response()->json([ 'success' => false, 'message' => 'Arquivo de backup inválido' ], 400); } DB::beginTransaction(); try { $stats = [ 'accounts' => 0, 'asset_accounts' => 0, 'categories' => 0, 'cost_centers' => 0, 'credit_cards' => 0, 'liability_accounts' => 0, 'budgets' => 0, 'goals' => 0, 'investments' => 0, 'transactions' => 0, ]; // Mapear IDs antigos -> novos IDs $accountMap = []; $categoryMap = []; $subcategoryMap = []; $costCenterMap = []; $creditCardMap = []; $liabilityAccountMap = []; $assetAccountMap = []; // 1. Importar contas bancárias if (isset($backup['accounts'])) { foreach ($backup['accounts'] as $account) { $oldId = $account['id']; unset($account['id'], $account['user_id'], $account['created_at'], $account['updated_at']); $newAccount = $user->accounts()->create($account); $accountMap[$oldId] = $newAccount->id; $stats['accounts']++; } } // 2. Importar contas de ativos if (isset($backup['asset_accounts'])) { foreach ($backup['asset_accounts'] as $assetAccount) { $oldId = $assetAccount['id']; unset($assetAccount['id'], $assetAccount['user_id'], $assetAccount['created_at'], $assetAccount['updated_at'], $assetAccount['asset_type']); $newAssetAccount = $user->assetAccounts()->create($assetAccount); $assetAccountMap[$oldId] = $newAssetAccount->id; $stats['asset_accounts']++; } } // 3. Importar categorias customizadas if (isset($backup['categories'])) { foreach ($backup['categories'] as $category) { if (!$category['is_custom']) continue; $oldId = $category['id']; $oldParentId = $category['parent_id'] ?? null; unset($category['id'], $category['user_id'], $category['created_at'], $category['updated_at']); // Se tem parent_id, precisa esperar para mapear depois if ($oldParentId) { $category['parent_id'] = null; // Temporário } $newCategory = $user->categories()->create($category); if ($oldParentId) { $subcategoryMap[$oldId] = ['new_id' => $newCategory->id, 'old_parent_id' => $oldParentId]; } else { $categoryMap[$oldId] = $newCategory->id; } $stats['categories']++; } } // Atualizar parent_id das subcategorias foreach ($subcategoryMap as $oldId => $data) { if (isset($categoryMap[$data['old_parent_id']])) { DB::table('categories') ->where('id', $data['new_id']) ->update(['parent_id' => $categoryMap[$data['old_parent_id']]]); $categoryMap[$oldId] = $data['new_id']; // Adicionar ao mapa principal } } // 4. Importar centros de custo if (isset($backup['cost_centers'])) { foreach ($backup['cost_centers'] as $costCenter) { $oldId = $costCenter['id']; $keywords = $costCenter['keywords'] ?? []; unset($costCenter['id'], $costCenter['user_id'], $costCenter['created_at'], $costCenter['updated_at'], $costCenter['keywords']); $newCostCenter = $user->costCenters()->create($costCenter); $costCenterMap[$oldId] = $newCostCenter->id; // Importar keywords foreach ($keywords as $keyword) { unset($keyword['id'], $keyword['cost_center_id'], $keyword['created_at'], $keyword['updated_at']); $newCostCenter->keywords()->create($keyword); } $stats['cost_centers']++; } } // 5. Importar cartões de crédito if (isset($backup['credit_cards'])) { foreach ($backup['credit_cards'] as $creditCard) { $oldId = $creditCard['id']; $oldAccountId = $creditCard['account_id']; unset($creditCard['id'], $creditCard['user_id'], $creditCard['created_at'], $creditCard['updated_at'], $creditCard['account']); // Mapear account_id if (isset($accountMap[$oldAccountId])) { $creditCard['account_id'] = $accountMap[$oldAccountId]; } else { continue; // Pular se conta não foi importada } $newCreditCard = $user->creditCards()->create($creditCard); $creditCardMap[$oldId] = $newCreditCard->id; $stats['credit_cards']++; } } // 6. Importar contas de passivos if (isset($backup['liability_accounts'])) { foreach ($backup['liability_accounts'] as $liabilityAccount) { $oldId = $liabilityAccount['id']; unset($liabilityAccount['id'], $liabilityAccount['user_id'], $liabilityAccount['created_at'], $liabilityAccount['updated_at']); $newLiabilityAccount = $user->liabilityAccounts()->create($liabilityAccount); $liabilityAccountMap[$oldId] = $newLiabilityAccount->id; $stats['liability_accounts']++; } } // 7. Importar orçamentos if (isset($backup['budgets'])) { foreach ($backup['budgets'] as $budget) { $oldCategoryId = $budget['category_id']; $oldSubcategoryId = $budget['subcategory_id'] ?? null; unset($budget['id'], $budget['user_id'], $budget['created_at'], $budget['updated_at'], $budget['category'], $budget['subcategory']); // Mapear IDs if (isset($categoryMap[$oldCategoryId])) { $budget['category_id'] = $categoryMap[$oldCategoryId]; } else { continue; } if ($oldSubcategoryId && isset($categoryMap[$oldSubcategoryId])) { $budget['subcategory_id'] = $categoryMap[$oldSubcategoryId]; } $user->budgets()->create($budget); $stats['budgets']++; } } // 8. Importar objetivos if (isset($backup['goals'])) { foreach ($backup['goals'] as $goal) { unset($goal['id'], $goal['user_id'], $goal['created_at'], $goal['updated_at']); $user->goals()->create($goal); $stats['goals']++; } } // 9. Importar investimentos if (isset($backup['investments'])) { foreach ($backup['investments'] as $investment) { $oldId = $investment['id']; $oldAssetAccountId = $investment['asset_account_id']; $priceHistories = $investment['price_histories'] ?? []; unset($investment['id'], $investment['user_id'], $investment['created_at'], $investment['updated_at'], $investment['asset_account'], $investment['investment_type'], $investment['price_histories']); // Mapear asset_account_id if (isset($assetAccountMap[$oldAssetAccountId])) { $investment['asset_account_id'] = $assetAccountMap[$oldAssetAccountId]; } else { continue; } $newInvestment = $user->investments()->create($investment); // Importar histórico de preços foreach ($priceHistories as $history) { unset($history['id'], $history['investment_id'], $history['created_at'], $history['updated_at']); $newInvestment->priceHistories()->create($history); } $stats['investments']++; } } // 10. Importar transações if (isset($backup['transactions'])) { foreach ($backup['transactions'] as $transaction) { $oldAccountId = $transaction['account_id'] ?? null; $oldCategoryId = $transaction['category_id'] ?? null; $oldSubcategoryId = $transaction['subcategory_id'] ?? null; $oldCostCenterId = $transaction['cost_center_id'] ?? null; $oldCreditCardId = $transaction['credit_card_id'] ?? null; $oldLiabilityAccountId = $transaction['liability_account_id'] ?? null; unset($transaction['id'], $transaction['user_id'], $transaction['created_at'], $transaction['updated_at'], $transaction['account'], $transaction['category'], $transaction['subcategory'], $transaction['cost_center'], $transaction['credit_card'], $transaction['liability_account']); // Mapear IDs if ($oldAccountId && isset($accountMap[$oldAccountId])) { $transaction['account_id'] = $accountMap[$oldAccountId]; } elseif ($oldAccountId) { continue; } if ($oldCategoryId && isset($categoryMap[$oldCategoryId])) { $transaction['category_id'] = $categoryMap[$oldCategoryId]; } if ($oldSubcategoryId && isset($categoryMap[$oldSubcategoryId])) { $transaction['subcategory_id'] = $categoryMap[$oldSubcategoryId]; } if ($oldCostCenterId && isset($costCenterMap[$oldCostCenterId])) { $transaction['cost_center_id'] = $costCenterMap[$oldCostCenterId]; } if ($oldCreditCardId && isset($creditCardMap[$oldCreditCardId])) { $transaction['credit_card_id'] = $creditCardMap[$oldCreditCardId]; } if ($oldLiabilityAccountId && isset($liabilityAccountMap[$oldLiabilityAccountId])) { $transaction['liability_account_id'] = $liabilityAccountMap[$oldLiabilityAccountId]; } $user->transactions()->create($transaction); $stats['transactions']++; } } DB::commit(); return response()->json([ 'success' => true, 'message' => 'Backup importado com sucesso', 'stats' => $stats ]); } catch (\Exception $e) { DB::rollBack(); throw $e; } } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Erro ao importar backup', 'error' => $e->getMessage() ], 500); } } }