Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
1 line
151 KiB
JSON
1 line
151 KiB
JSON
{"repo": "alceujrab/laracrm", "files": {"app/Http/Controllers/AppSettingsController.php": {"bbd317c6685c4f2d667e455af28208fb249fe99d": {"t": 1785746161.2559805, "n": 17170, "h": "b5ae5f65059b2c48", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\AwsSnsService;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse App\\Services\\ThemeSettingsService;\nuse Illuminate\\Http\\RedirectResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-3.6-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getAwsSettings()\n {\n return response()->json([\n 'aws_access_key_id' => (string) AppSetting::getSetting('aws_access_key_id', ''),\n 'aws_secret_access_key' => (string) AppSetting::getSetting('aws_secret_access_key', ''),\n 'aws_region' => (string) AppSetting::getSetting('aws_region', 'sa-east-1'),\n 'aws_account_id' => (string) AppSetting::getSetting('aws_account_id', '195202617322'),\n 'aws_sns_sms_sender_id' => (string) AppSetting::getSetting('aws_sns_sms_sender_id', 'EliteVeic'),\n 'aws_sns_sms_type' => (string) AppSetting::getSetting('aws_sns_sms_type', 'Transactional'),\n 'aws_sns_platform_app_arn_fcm' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_fcm', ''),\n 'aws_sns_platform_app_arn_apns' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_apns', ''),\n ]);\n }\n\n public function updateAwsSettings(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'nullable|string|max:500',\n 'aws_secret_access_key' => 'nullable|string|max:500',\n 'aws_region' => 'nullable|string|max:50',\n 'aws_account_id' => 'nullable|string|max:20',\n 'aws_sns_sms_sender_id' => 'nullable|string|max:11',\n 'aws_sns_sms_type' => 'nullable|string|in:Transactional,Promotional',\n 'aws_sns_platform_app_arn_fcm' => 'nullable|string|max:500',\n 'aws_sns_platform_app_arn_apns' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('aws_access_key_id', $request->input('aws_access_key_id', ''));\n AppSetting::setSetting('aws_secret_access_key', $request->input('aws_secret_access_key', ''));\n AppSetting::setSetting('aws_region', $request->input('aws_region', 'sa-east-1'));\n AppSetting::setSetting('aws_account_id', $request->input('aws_account_id', ''));\n AppSetting::setSetting('aws_sns_sms_sender_id', $request->input('aws_sns_sms_sender_id', ''));\n AppSetting::setSetting('aws_sns_sms_type', $request->input('aws_sns_sms_type', 'Transactional'));\n AppSetting::setSetting('aws_sns_platform_app_arn_fcm', $request->input('aws_sns_platform_app_arn_fcm', ''));\n AppSetting::setSetting('aws_sns_platform_app_arn_apns', $request->input('aws_sns_platform_app_arn_apns', ''));\n\n return response()->json(['message' => 'Credenciais AWS salvas com sucesso!']);\n }\n\n public function testAwsConnection(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'required|string',\n 'aws_secret_access_key' => 'required|string',\n 'aws_region' => 'nullable|string|max:50',\n ]);\n\n $ok = app(AwsSnsService::class)->testCredentials(\n $request->aws_access_key_id,\n $request->aws_secret_access_key,\n $request->input('aws_region', 'sa-east-1'),\n );\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com AWS SNS estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique Access Key, Secret Key e região (sa-east-1).'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'aws'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:aws,clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = match ($request->provider) {\n 'clicksend' => 'ClickSend',\n 'smsmais' => 'SMS Mais',\n default => 'AWS SNS',\n };\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n\n public function updateThemePresets(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n 'tokens' => ['required', 'array'],\n ]);\n\n $themes->saveThemeTokens($validated['theme_id'], $validated['tokens']);\n\n return back()->with('success', 'Paleta do tema salva com sucesso!');\n }\n\n public function resetThemePreset(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n ]);\n\n $themes->resetTheme($validated['theme_id']);\n\n return back()->with('success', 'Tema restaurado para os valores padrão de fábrica.');\n }\n}\n"}, "78c7b6b6502b44e7e365b1b2df684c3069a9db8d": {"t": 1785760282.17778, "n": 17170, "h": "b5ae5f65059b2c48", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\AwsSnsService;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse App\\Services\\ThemeSettingsService;\nuse Illuminate\\Http\\RedirectResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-3.6-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getAwsSettings()\n {\n return response()->json([\n 'aws_access_key_id' => (string) AppSetting::getSetting('aws_access_key_id', ''),\n 'aws_secret_access_key' => (string) AppSetting::getSetting('aws_secret_access_key', ''),\n 'aws_region' => (string) AppSetting::getSetting('aws_region', 'sa-east-1'),\n 'aws_account_id' => (string) AppSetting::getSetting('aws_account_id', '195202617322'),\n 'aws_sns_sms_sender_id' => (string) AppSetting::getSetting('aws_sns_sms_sender_id', 'EliteVeic'),\n 'aws_sns_sms_type' => (string) AppSetting::getSetting('aws_sns_sms_type', 'Transactional'),\n 'aws_sns_platform_app_arn_fcm' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_fcm', ''),\n 'aws_sns_platform_app_arn_apns' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_apns', ''),\n ]);\n }\n\n public function updateAwsSettings(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'nullable|string|max:500',\n 'aws_secret_access_key' => 'nullable|string|max:500',\n 'aws_region' => 'nullable|string|max:50',\n 'aws_account_id' => 'nullable|string|max:20',\n 'aws_sns_sms_sender_id' => 'nullable|string|max:11',\n 'aws_sns_sms_type' => 'nullable|string|in:Transactional,Promotional',\n 'aws_sns_platform_app_arn_fcm' => 'nullable|string|max:500',\n 'aws_sns_platform_app_arn_apns' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('aws_access_key_id', $request->input('aws_access_key_id', ''));\n AppSetting::setSetting('aws_secret_access_key', $request->input('aws_secret_access_key', ''));\n AppSetting::setSetting('aws_region', $request->input('aws_region', 'sa-east-1'));\n AppSetting::setSetting('aws_account_id', $request->input('aws_account_id', ''));\n AppSetting::setSetting('aws_sns_sms_sender_id', $request->input('aws_sns_sms_sender_id', ''));\n AppSetting::setSetting('aws_sns_sms_type', $request->input('aws_sns_sms_type', 'Transactional'));\n AppSetting::setSetting('aws_sns_platform_app_arn_fcm', $request->input('aws_sns_platform_app_arn_fcm', ''));\n AppSetting::setSetting('aws_sns_platform_app_arn_apns', $request->input('aws_sns_platform_app_arn_apns', ''));\n\n return response()->json(['message' => 'Credenciais AWS salvas com sucesso!']);\n }\n\n public function testAwsConnection(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'required|string',\n 'aws_secret_access_key' => 'required|string',\n 'aws_region' => 'nullable|string|max:50',\n ]);\n\n $ok = app(AwsSnsService::class)->testCredentials(\n $request->aws_access_key_id,\n $request->aws_secret_access_key,\n $request->input('aws_region', 'sa-east-1'),\n );\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com AWS SNS estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique Access Key, Secret Key e região (sa-east-1).'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'aws'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:aws,clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = match ($request->provider) {\n 'clicksend' => 'ClickSend',\n 'smsmais' => 'SMS Mais',\n default => 'AWS SNS',\n };\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n\n public function updateThemePresets(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n 'tokens' => ['required', 'array'],\n ]);\n\n $themes->saveThemeTokens($validated['theme_id'], $validated['tokens']);\n\n return back()->with('success', 'Paleta do tema salva com sucesso!');\n }\n\n public function resetThemePreset(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n ]);\n\n $themes->resetTheme($validated['theme_id']);\n\n return back()->with('success', 'Tema restaurado para os valores padrão de fábrica.');\n }\n}\n"}, "d6960095eb18ce5bfdee09139197aa14cd73f9da": {"t": 1785760283.979137, "n": 17166, "h": "12c1612f7b0a433a", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\AwsSnsService;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse App\\Services\\ThemeSettingsService;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getAwsSettings()\n {\n return response()->json([\n 'aws_access_key_id' => (string) AppSetting::getSetting('aws_access_key_id', ''),\n 'aws_secret_access_key' => (string) AppSetting::getSetting('aws_secret_access_key', ''),\n 'aws_region' => (string) AppSetting::getSetting('aws_region', 'sa-east-1'),\n 'aws_account_id' => (string) AppSetting::getSetting('aws_account_id', '195202617322'),\n 'aws_sns_sms_sender_id' => (string) AppSetting::getSetting('aws_sns_sms_sender_id', 'EliteVeic'),\n 'aws_sns_sms_type' => (string) AppSetting::getSetting('aws_sns_sms_type', 'Transactional'),\n 'aws_sns_platform_app_arn_fcm' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_fcm', ''),\n 'aws_sns_platform_app_arn_apns' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_apns', ''),\n ]);\n }\n\n public function updateAwsSettings(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'nullable|string|max:500',\n 'aws_secret_access_key' => 'nullable|string|max:500',\n 'aws_region' => 'nullable|string|max:50',\n 'aws_account_id' => 'nullable|string|max:20',\n 'aws_sns_sms_sender_id' => 'nullable|string|max:11',\n 'aws_sns_sms_type' => 'nullable|string|in:Transactional,Promotional',\n 'aws_sns_platform_app_arn_fcm' => 'nullable|string|max:500',\n 'aws_sns_platform_app_arn_apns' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('aws_access_key_id', $request->input('aws_access_key_id', ''));\n AppSetting::setSetting('aws_secret_access_key', $request->input('aws_secret_access_key', ''));\n AppSetting::setSetting('aws_region', $request->input('aws_region', 'sa-east-1'));\n AppSetting::setSetting('aws_account_id', $request->input('aws_account_id', ''));\n AppSetting::setSetting('aws_sns_sms_sender_id', $request->input('aws_sns_sms_sender_id', ''));\n AppSetting::setSetting('aws_sns_sms_type', $request->input('aws_sns_sms_type', 'Transactional'));\n AppSetting::setSetting('aws_sns_platform_app_arn_fcm', $request->input('aws_sns_platform_app_arn_fcm', ''));\n AppSetting::setSetting('aws_sns_platform_app_arn_apns', $request->input('aws_sns_platform_app_arn_apns', ''));\n\n return response()->json(['message' => 'Credenciais AWS salvas com sucesso!']);\n }\n\n public function testAwsConnection(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'required|string',\n 'aws_secret_access_key' => 'required|string',\n 'aws_region' => 'nullable|string|max:50',\n ]);\n\n $ok = app(AwsSnsService::class)->testCredentials(\n $request->aws_access_key_id,\n $request->aws_secret_access_key,\n $request->input('aws_region', 'sa-east-1'),\n );\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com AWS SNS estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique Access Key, Secret Key e região (sa-east-1).'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'aws'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:aws,clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = match ($request->provider) {\n 'clicksend' => 'ClickSend',\n 'smsmais' => 'SMS Mais',\n default => 'AWS SNS',\n };\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n\n public function updateThemePresets(Request $request, ThemeSettingsService $themes): \\Illuminate\\Http\\RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n 'tokens' => ['required', 'array'],\n ]);\n\n $themes->saveThemeTokens($validated['theme_id'], $validated['tokens']);\n\n return back()->with('success', 'Paleta do tema salva com sucesso!');\n }\n\n public function resetThemePreset(Request $request, ThemeSettingsService $themes): \\Illuminate\\Http\\RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n ]);\n\n $themes->resetTheme($validated['theme_id']);\n\n return back()->with('success', 'Tema restaurado para os valores padrão de fábrica.');\n }\n}\n"}, "8bc027be0174ca9df46b88b47688635303cae8b8": {"t": 1785760285.4850564, "n": 12843, "h": "a877dcfb86c72663", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'clicksend'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = $request->provider === 'smsmais' ? 'SMS Mais' : 'ClickSend';\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n}\n"}, "4881c49fe26ae91685bf7693be68d81b58cdca87": {"t": 1785760286.717684, "n": 11191, "h": "850e32b94932ae9a", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\ClickSendService;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n}\n"}, "623c06932bf95baee2e1e64b551f2b9113788380": {"t": 1785760288.2910323, "n": 9508, "h": "2cde3fcf3efcee2a", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n}\n"}, "eb0f6aec29cbeedc3958b8a508d13bd7e5289ffe": {"t": 1785760289.9083607, "n": 8708, "h": "cb992ec21fa4c9b1", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (!is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (!is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = \\Illuminate\\Support\\Facades\\Http::withHeaders([\n 'Authorization' => 'Bearer ' . $apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (!$response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: ' . $response->body());\n }\n } elseif ($provider === 'openai') {\n $response = \\Illuminate\\Support\\Facades\\Http::withHeaders([\n 'Authorization' => 'Bearer ' . $apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (!$response->successful()) {\n throw new \\Exception('Erro na API OpenAI: ' . $response->body());\n }\n } elseif ($provider === 'claude') {\n $response = \\Illuminate\\Support\\Facades\\Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (!$response->successful()) {\n throw new \\Exception('Erro na API Claude: ' . $response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = \\Illuminate\\Support\\Facades\\Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=' . $apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (!$response->successful()) {\n throw new \\Exception('Erro na API Gemini: ' . $response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: ' . $e->getMessage()], 400);\n }\n }\n}\n"}, "7171a3c67b73924a2e004efd94ee6ad381f4e9f6": {"t": 1785760291.355466, "n": 3769, "h": "59f003a1a426f3fd", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (!is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (!is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n}\n"}, "ddb46ae97d985ef2ed3992097b60d1cc11cd4574": {"t": 1785760292.6869047, "n": 2671, "h": "5a26d3b164fb4d59", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|image|mimes:jpeg,png,jpg,svg|max:2048',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n // Deletar logo antiga se existir\n $oldLogo = AppSetting::getSetting('app_logo');\n if ($oldLogo) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n $path = $request->file('app_logo')->store('app_logos', 'public');\n AppSetting::setSetting('app_logo', $path);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n}\n"}, "034c4a08f45985734723d590ab04bd00b87eace2": {"t": 1785760294.263483, "n": 1566, "h": "904892fc5a9251f8", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|image|mimes:jpeg,png,jpg,svg|max:2048',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n // Deletar logo antiga se existir\n $oldLogo = AppSetting::getSetting('app_logo');\n if ($oldLogo) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n $path = $request->file('app_logo')->store('app_logos', 'public');\n AppSetting::setSetting('app_logo', $path);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n}\n"}, "425e9fbc6b6524129eb59f151c26206cdcf442ef": {"t": 1785760295.8376424, "n": 1351, "h": "1359b242ea404ce5", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|image|mimes:jpeg,png,jpg,svg|max:2048',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n\n if ($request->hasFile('app_logo')) {\n // Deletar logo antiga se existir\n $oldLogo = AppSetting::getSetting('app_logo');\n if ($oldLogo) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n $path = $request->file('app_logo')->store('app_logos', 'public');\n AppSetting::setSetting('app_logo', $path);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n}\n"}, "e81c70864b638c3995d654989e9892505e602e24": {"t": 1785760297.3827035, "n": 960, "h": "1394d53c8c8ac36b", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse Illuminate\\Http\\Request;\n\nuse App\\Models\\AppSetting;\nuse Illuminate\\Support\\Facades\\Storage;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|image|mimes:jpeg,png,jpg,svg|max:2048',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n\n if ($request->hasFile('app_logo')) {\n // Deletar logo antiga se existir\n $oldLogo = AppSetting::getSetting('app_logo');\n if ($oldLogo) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n $path = $request->file('app_logo')->store('app_logos', 'public');\n AppSetting::setSetting('app_logo', $path);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n}\n"}, "4e397044aed6191ee5e44ad5bc7164e2c3a02123": {"t": 1786067610.1586, "n": 17170, "h": "b5ae5f65059b2c48", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\AwsSnsService;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse App\\Services\\ThemeSettingsService;\nuse Illuminate\\Http\\RedirectResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-3.6-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getAwsSettings()\n {\n return response()->json([\n 'aws_access_key_id' => (string) AppSetting::getSetting('aws_access_key_id', ''),\n 'aws_secret_access_key' => (string) AppSetting::getSetting('aws_secret_access_key', ''),\n 'aws_region' => (string) AppSetting::getSetting('aws_region', 'sa-east-1'),\n 'aws_account_id' => (string) AppSetting::getSetting('aws_account_id', '195202617322'),\n 'aws_sns_sms_sender_id' => (string) AppSetting::getSetting('aws_sns_sms_sender_id', 'EliteVeic'),\n 'aws_sns_sms_type' => (string) AppSetting::getSetting('aws_sns_sms_type', 'Transactional'),\n 'aws_sns_platform_app_arn_fcm' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_fcm', ''),\n 'aws_sns_platform_app_arn_apns' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_apns', ''),\n ]);\n }\n\n public function updateAwsSettings(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'nullable|string|max:500',\n 'aws_secret_access_key' => 'nullable|string|max:500',\n 'aws_region' => 'nullable|string|max:50',\n 'aws_account_id' => 'nullable|string|max:20',\n 'aws_sns_sms_sender_id' => 'nullable|string|max:11',\n 'aws_sns_sms_type' => 'nullable|string|in:Transactional,Promotional',\n 'aws_sns_platform_app_arn_fcm' => 'nullable|string|max:500',\n 'aws_sns_platform_app_arn_apns' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('aws_access_key_id', $request->input('aws_access_key_id', ''));\n AppSetting::setSetting('aws_secret_access_key', $request->input('aws_secret_access_key', ''));\n AppSetting::setSetting('aws_region', $request->input('aws_region', 'sa-east-1'));\n AppSetting::setSetting('aws_account_id', $request->input('aws_account_id', ''));\n AppSetting::setSetting('aws_sns_sms_sender_id', $request->input('aws_sns_sms_sender_id', ''));\n AppSetting::setSetting('aws_sns_sms_type', $request->input('aws_sns_sms_type', 'Transactional'));\n AppSetting::setSetting('aws_sns_platform_app_arn_fcm', $request->input('aws_sns_platform_app_arn_fcm', ''));\n AppSetting::setSetting('aws_sns_platform_app_arn_apns', $request->input('aws_sns_platform_app_arn_apns', ''));\n\n return response()->json(['message' => 'Credenciais AWS salvas com sucesso!']);\n }\n\n public function testAwsConnection(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'required|string',\n 'aws_secret_access_key' => 'required|string',\n 'aws_region' => 'nullable|string|max:50',\n ]);\n\n $ok = app(AwsSnsService::class)->testCredentials(\n $request->aws_access_key_id,\n $request->aws_secret_access_key,\n $request->input('aws_region', 'sa-east-1'),\n );\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com AWS SNS estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique Access Key, Secret Key e região (sa-east-1).'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'aws'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:aws,clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = match ($request->provider) {\n 'clicksend' => 'ClickSend',\n 'smsmais' => 'SMS Mais',\n default => 'AWS SNS',\n };\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n\n public function updateThemePresets(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n 'tokens' => ['required', 'array'],\n ]);\n\n $themes->saveThemeTokens($validated['theme_id'], $validated['tokens']);\n\n return back()->with('success', 'Paleta do tema salva com sucesso!');\n }\n\n public function resetThemePreset(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n ]);\n\n $themes->resetTheme($validated['theme_id']);\n\n return back()->with('success', 'Tema restaurado para os valores padrão de fábrica.');\n }\n}\n"}, "39d30cab142e3a6e77fe66505999f390ddbc90a7": {"t": 1786068382.7197664, "n": 17170, "h": "b5ae5f65059b2c48", "c": "<?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\AppSetting;\nuse App\\Services\\AwsSnsService;\nuse App\\Services\\ClickSendService;\nuse App\\Services\\SmsMaisService;\nuse App\\Services\\ThemeSettingsService;\nuse Illuminate\\Http\\RedirectResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Support\\Facades\\Http;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Illuminate\\Support\\Str;\n\nclass AppSettingsController extends Controller\n{\n public function update(Request $request)\n {\n $request->validate([\n 'app_name' => 'required|string|max:255',\n 'app_logo' => 'nullable|file|mimes:jpeg,png,jpg,svg,webp,gif|max:4096',\n 'company_cnpj' => 'nullable|string|max:32',\n 'company_address' => 'nullable|string|max:255',\n 'company_email' => 'nullable|email|max:255',\n 'company_whatsapp' => 'nullable|string|max:32',\n 'company_site' => 'nullable|string|max:255',\n 'company_instagram' => 'nullable|string|max:255',\n 'company_facebook' => 'nullable|string|max:255',\n 'sla_first_response_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_queue_wait_minutes' => 'nullable|integer|min:1|max:720',\n 'sla_critical_auto_task_minutes' => 'nullable|integer|min:0|max:1440',\n ]);\n\n AppSetting::setSetting('app_name', $request->app_name);\n AppSetting::setSetting('company_cnpj', (string) $request->input('company_cnpj', ''));\n AppSetting::setSetting('company_address', (string) $request->input('company_address', ''));\n AppSetting::setSetting('company_email', (string) $request->input('company_email', ''));\n AppSetting::setSetting('company_whatsapp', (string) $request->input('company_whatsapp', ''));\n AppSetting::setSetting('company_site', (string) $request->input('company_site', ''));\n AppSetting::setSetting('company_instagram', (string) $request->input('company_instagram', ''));\n AppSetting::setSetting('company_facebook', (string) $request->input('company_facebook', ''));\n AppSetting::setSetting('sla_first_response_minutes', (string) ($request->input('sla_first_response_minutes', 5)));\n AppSetting::setSetting('sla_queue_wait_minutes', (string) ($request->input('sla_queue_wait_minutes', 10)));\n AppSetting::setSetting('sla_critical_auto_task_minutes', (string) ($request->input('sla_critical_auto_task_minutes', 20)));\n\n if ($request->hasFile('app_logo')) {\n $file = $request->file('app_logo');\n $oldLogo = AppSetting::getSetting('app_logo');\n\n $destDir = storage_path('app/public/app_logos');\n if (! is_dir($destDir)) {\n @mkdir($destDir, 0775, true);\n }\n\n $ext = strtolower($file->getClientOriginalExtension() ?: $file->extension() ?: 'png');\n $filename = Str::random(40).'.'.$ext;\n $absolute = $destDir.DIRECTORY_SEPARATOR.$filename;\n\n try {\n $file->move($destDir, $filename);\n } catch (\\Throwable $e) {\n Log::error('AppSettings logo move failed', ['error' => $e->getMessage()]);\n\n return back()->withErrors(['app_logo' => 'Falha ao salvar a logomarca: '.$e->getMessage()])->withInput();\n }\n\n if (! is_file($absolute) || filesize($absolute) === 0) {\n Log::error('AppSettings logo not persisted', ['path' => $absolute]);\n\n return back()->withErrors(['app_logo' => 'A logomarca não foi gravada no servidor. Verifique permissões de storage/app/public/app_logos.'])->withInput();\n }\n\n if ($oldLogo && $oldLogo !== 'app_logos/'.$filename) {\n Storage::disk('public')->delete($oldLogo);\n }\n\n AppSetting::setSetting('app_logo', 'app_logos/'.$filename);\n }\n\n return back()->with('success', 'Configurações atualizadas com sucesso!');\n }\n\n public function getAiSettings()\n {\n return response()->json([\n 'ai_market_provider' => AppSetting::getSetting('ai_market_provider', 'deepseek'),\n 'ai_api_key_deepseek' => AppSetting::getSetting('ai_api_key_deepseek', ''),\n 'ai_api_key_openai' => AppSetting::getSetting('ai_api_key_openai', ''),\n 'ai_api_key_claude' => AppSetting::getSetting('ai_api_key_claude', ''),\n 'ai_api_key_gemini' => AppSetting::getSetting('ai_api_key_gemini', ''),\n ]);\n }\n\n public function updateAiSettings(Request $request)\n {\n $request->validate([\n 'ai_market_provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'ai_api_key_deepseek' => 'nullable|string',\n 'ai_api_key_openai' => 'nullable|string',\n 'ai_api_key_claude' => 'nullable|string',\n 'ai_api_key_gemini' => 'nullable|string',\n ]);\n\n AppSetting::setSetting('ai_market_provider', $request->ai_market_provider);\n AppSetting::setSetting('ai_api_key_deepseek', $request->input('ai_api_key_deepseek') ?? '');\n AppSetting::setSetting('ai_api_key_openai', $request->input('ai_api_key_openai') ?? '');\n AppSetting::setSetting('ai_api_key_claude', $request->input('ai_api_key_claude') ?? '');\n AppSetting::setSetting('ai_api_key_gemini', $request->input('ai_api_key_gemini') ?? '');\n\n return response()->json(['message' => 'Configurações salvas com sucesso!']);\n }\n\n public function testAiConnection(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:deepseek,openai,claude,gemini',\n 'api_key' => 'required|string',\n ]);\n\n $provider = $request->provider;\n $apiKey = $request->api_key;\n\n try {\n $prompt = 'Responda apenas com a palavra OK.';\n $timeout = 10;\n\n if ($provider === 'deepseek') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.deepseek.com/v1/chat/completions', [\n 'model' => 'deepseek-chat',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API DeepSeek: '.$response->body());\n }\n } elseif ($provider === 'openai') {\n $response = Http::withHeaders([\n 'Authorization' => 'Bearer '.$apiKey,\n 'Content-Type' => 'application/json',\n ])->timeout($timeout)->post('https://api.openai.com/v1/chat/completions', [\n 'model' => 'gpt-4o-mini',\n 'messages' => [\n ['role' => 'user', 'content' => $prompt],\n ],\n 'max_tokens' => 5,\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API OpenAI: '.$response->body());\n }\n } elseif ($provider === 'claude') {\n $response = Http::withHeaders([\n 'x-api-key' => $apiKey,\n 'Content-Type' => 'application/json',\n 'anthropic-version' => '2023-06-01',\n ])->timeout($timeout)->post('https://api.anthropic.com/v1/messages', [\n 'model' => 'claude-3-haiku-20240307',\n 'max_tokens' => 5,\n 'messages' => [['role' => 'user', 'content' => $prompt]],\n ]);\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Claude: '.$response->body());\n }\n } elseif ($provider === 'gemini') {\n $response = Http::timeout($timeout)->post(\n 'https://generativelanguage.googleapis.com/v1beta/models/gemini-3.6-flash:generateContent?key='.$apiKey,\n ['contents' => [['parts' => [['text' => $prompt]]]]]\n );\n\n if (! $response->successful()) {\n throw new \\Exception('Erro na API Gemini: '.$response->body());\n }\n } else {\n throw new \\Exception('Provedor não suportado.');\n }\n\n return response()->json(['message' => 'Conexão testada com sucesso! O provedor respondeu corretamente.']);\n } catch (\\Throwable $e) {\n return response()->json(['error' => 'Falha na conexão: '.$e->getMessage()], 400);\n }\n }\n\n public function getGoogleSettings()\n {\n return response()->json([\n 'google_client_id' => (string) AppSetting::getSetting('google_client_id', ''),\n 'google_client_secret' => (string) AppSetting::getSetting('google_client_secret', ''),\n 'google_redirect_uri' => url('/auth/google/callback'),\n ]);\n }\n\n public function updateGoogleSettings(Request $request)\n {\n $request->validate([\n 'google_client_id' => 'nullable|string|max:500',\n 'google_client_secret' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('google_client_id', $request->input('google_client_id', ''));\n AppSetting::setSetting('google_client_secret', $request->input('google_client_secret', ''));\n\n return response()->json(['message' => 'Credenciais do Google salvas com sucesso!']);\n }\n\n public function getClickSendSettings()\n {\n return response()->json([\n 'clicksend_username' => (string) AppSetting::getSetting('clicksend_username', ''),\n 'clicksend_api_key' => (string) AppSetting::getSetting('clicksend_api_key', ''),\n 'clicksend_default_from' => (string) AppSetting::getSetting('clicksend_default_from', ''),\n ]);\n }\n\n public function updateClickSendSettings(Request $request)\n {\n $request->validate([\n 'clicksend_username' => 'nullable|string|max:500',\n 'clicksend_api_key' => 'nullable|string|max:500',\n 'clicksend_default_from' => 'nullable|string|max:50',\n ]);\n\n AppSetting::setSetting('clicksend_username', $request->input('clicksend_username', ''));\n AppSetting::setSetting('clicksend_api_key', $request->input('clicksend_api_key', ''));\n AppSetting::setSetting('clicksend_default_from', $request->input('clicksend_default_from', ''));\n\n return response()->json(['message' => 'Credenciais do ClickSend salvas com sucesso!']);\n }\n\n public function testClickSendConnection(Request $request)\n {\n $request->validate([\n 'username' => 'required|string',\n 'api_key' => 'required|string',\n ]);\n\n $ok = app(ClickSendService::class)\n ->testCredentials($request->username, $request->api_key);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com ClickSend estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique as credenciais.'], 422);\n }\n\n public function getSmsMaisSettings()\n {\n return response()->json([\n 'smsmais_token' => (string) AppSetting::getSetting('smsmais_token', ''),\n ]);\n }\n\n public function updateSmsMaisSettings(Request $request)\n {\n $request->validate([\n 'smsmais_token' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('smsmais_token', $request->input('smsmais_token', ''));\n\n return response()->json(['message' => 'Credenciais do SMS Mais salvas com sucesso!']);\n }\n\n public function testSmsMaisConnection(Request $request)\n {\n $request->validate([\n 'token' => 'required|string',\n ]);\n\n $ok = app(SmsMaisService::class)->testCredentials($request->token);\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com SMS Mais estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Token inválido ou conta bloqueada.'], 422);\n }\n\n public function getAwsSettings()\n {\n return response()->json([\n 'aws_access_key_id' => (string) AppSetting::getSetting('aws_access_key_id', ''),\n 'aws_secret_access_key' => (string) AppSetting::getSetting('aws_secret_access_key', ''),\n 'aws_region' => (string) AppSetting::getSetting('aws_region', 'sa-east-1'),\n 'aws_account_id' => (string) AppSetting::getSetting('aws_account_id', '195202617322'),\n 'aws_sns_sms_sender_id' => (string) AppSetting::getSetting('aws_sns_sms_sender_id', 'EliteVeic'),\n 'aws_sns_sms_type' => (string) AppSetting::getSetting('aws_sns_sms_type', 'Transactional'),\n 'aws_sns_platform_app_arn_fcm' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_fcm', ''),\n 'aws_sns_platform_app_arn_apns' => (string) AppSetting::getSetting('aws_sns_platform_app_arn_apns', ''),\n ]);\n }\n\n public function updateAwsSettings(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'nullable|string|max:500',\n 'aws_secret_access_key' => 'nullable|string|max:500',\n 'aws_region' => 'nullable|string|max:50',\n 'aws_account_id' => 'nullable|string|max:20',\n 'aws_sns_sms_sender_id' => 'nullable|string|max:11',\n 'aws_sns_sms_type' => 'nullable|string|in:Transactional,Promotional',\n 'aws_sns_platform_app_arn_fcm' => 'nullable|string|max:500',\n 'aws_sns_platform_app_arn_apns' => 'nullable|string|max:500',\n ]);\n\n AppSetting::setSetting('aws_access_key_id', $request->input('aws_access_key_id', ''));\n AppSetting::setSetting('aws_secret_access_key', $request->input('aws_secret_access_key', ''));\n AppSetting::setSetting('aws_region', $request->input('aws_region', 'sa-east-1'));\n AppSetting::setSetting('aws_account_id', $request->input('aws_account_id', ''));\n AppSetting::setSetting('aws_sns_sms_sender_id', $request->input('aws_sns_sms_sender_id', ''));\n AppSetting::setSetting('aws_sns_sms_type', $request->input('aws_sns_sms_type', 'Transactional'));\n AppSetting::setSetting('aws_sns_platform_app_arn_fcm', $request->input('aws_sns_platform_app_arn_fcm', ''));\n AppSetting::setSetting('aws_sns_platform_app_arn_apns', $request->input('aws_sns_platform_app_arn_apns', ''));\n\n return response()->json(['message' => 'Credenciais AWS salvas com sucesso!']);\n }\n\n public function testAwsConnection(Request $request)\n {\n $request->validate([\n 'aws_access_key_id' => 'required|string',\n 'aws_secret_access_key' => 'required|string',\n 'aws_region' => 'nullable|string|max:50',\n ]);\n\n $ok = app(AwsSnsService::class)->testCredentials(\n $request->aws_access_key_id,\n $request->aws_secret_access_key,\n $request->input('aws_region', 'sa-east-1'),\n );\n\n if ($ok) {\n return response()->json(['message' => 'Conexão com AWS SNS estabelecida com sucesso!']);\n }\n\n return response()->json(['message' => 'Falha na conexão. Verifique Access Key, Secret Key e região (sa-east-1).'], 422);\n }\n\n public function getSmsProvider()\n {\n return response()->json([\n 'provider' => (string) AppSetting::getSetting('sms_primary_provider', 'aws'),\n ]);\n }\n\n public function setSmsProvider(Request $request)\n {\n $request->validate([\n 'provider' => 'required|string|in:aws,clicksend,smsmais',\n ]);\n\n AppSetting::setSetting('sms_primary_provider', $request->provider);\n\n $name = match ($request->provider) {\n 'clicksend' => 'ClickSend',\n 'smsmais' => 'SMS Mais',\n default => 'AWS SNS',\n };\n\n return response()->json(['message' => \"{$name} definido como provedor principal de SMS!\"]);\n }\n\n public function updateThemePresets(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n 'tokens' => ['required', 'array'],\n ]);\n\n $themes->saveThemeTokens($validated['theme_id'], $validated['tokens']);\n\n return back()->with('success', 'Paleta do tema salva com sucesso!');\n }\n\n public function resetThemePreset(Request $request, ThemeSettingsService $themes): RedirectResponse\n {\n $validated = $request->validate([\n 'theme_id' => ['required', 'string', 'in:'.implode(',', ThemeSettingsService::THEME_IDS)],\n ]);\n\n $themes->resetTheme($validated['theme_id']);\n\n return back()->with('success', 'Tema restaurado para os valores padrão de fábrica.');\n }\n}\n"}}, "app/Services/Manu/ManuSettingsService.php": {"39d30cab142e3a6e77fe66505999f390ddbc90a7": {"t": 1786068315.6496782, "n": 9949, "h": "b9b0027fcc609ba8", "c": "<?php\n\nnamespace App\\Services\\Manu;\n\nuse App\\Models\\AppSetting;\nuse App\\Models\\SiteSetting;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Illuminate\\Support\\Facades\\Crypt;\n\nclass ManuSettingsService\n{\n private const CACHE_KEY = 'manu_settings_v1';\n\n /**\n * @return array<string, mixed>\n */\n public function all(): array\n {\n return Cache::remember(self::CACHE_KEY, 3600, function (): array {\n $raw = AppSetting::getSetting('manu_training', null);\n\n if (! is_string($raw) || $raw === '') {\n return $this->defaults();\n }\n\n $decoded = json_decode($raw, true);\n\n return is_array($decoded)\n ? array_replace_recursive($this->defaults(), $decoded)\n : $this->defaults();\n });\n }\n\n /**\n * @param array<string, mixed> $payload\n */\n public function update(array $payload): void\n {\n $current = $this->all();\n $merged = array_replace_recursive($current, $payload);\n\n foreach (['whatsapp_api_key', 'crm_api_key', 'training_api_key'] as $keyField) {\n $incoming = data_get($payload, \"ai.{$keyField}\");\n if ($incoming === null || $incoming === '' || $incoming === '********') {\n data_set($merged, \"ai.{$keyField}\", data_get($current, \"ai.{$keyField}\"));\n } elseif (is_string($incoming)) {\n data_set($merged, \"ai.{$keyField}\", Crypt::encryptString($incoming));\n }\n }\n\n AppSetting::setSetting('manu_training', json_encode($merged, JSON_UNESCAPED_UNICODE));\n Cache::forget(self::CACHE_KEY);\n }\n\n public const CACHE_KEY_NOME_DA_LOJA = 'manu_nome_da_loja';\n\n public function forgetCache(): void\n {\n Cache::forget(self::CACHE_KEY);\n Cache::forget(self::CACHE_KEY_NOME_DA_LOJA);\n }\n\n public function whatsappInstructions(): string\n {\n $custom = trim((string) data_get($this->all(), 'prompts.whatsapp', ''));\n\n $base = $custom !== ''\n ? $custom\n : (string) config('manu.instructions', '');\n\n return $this->appendFlowCatalog($this->comNomeDaLoja($base), 'whatsapp');\n }\n\n /**\n * Troca `{{loja}}` pelo nome que a loja usa para se apresentar.\n *\n * O prompt trazia o nome escrito à mão em três lugares, cada um de um\n * jeito — \"Elite Veículos e Locadora\", \"Elite\" e \"a loja\". Vindo do\n * cadastro do site, muda em um lugar só e a Manu para de se apresentar\n * como três empresas diferentes.\n */\n private function comNomeDaLoja(string $prompt): string\n {\n if (! str_contains($prompt, '{{loja}}')) {\n return $prompt;\n }\n\n return str_replace('{{loja}}', $this->nomeDaLoja(), $prompt);\n }\n\n public function nomeDaLoja(): string\n {\n return Cache::remember(self::CACHE_KEY_NOME_DA_LOJA, 3600, function (): string {\n $config = SiteSetting::query()->first();\n\n $nome = trim((string) ($config?->brand_name ?: $config?->site_name ?: ''));\n\n return $nome !== '' ? $nome : (string) config('app.name', 'loja');\n });\n }\n\n public function crmInstructions(): string\n {\n $custom = trim((string) data_get($this->all(), 'prompts.crm', ''));\n\n $base = $custom !== ''\n ? $custom\n : (string) config('manu.crm_instructions', '');\n\n return $this->appendFlowCatalog($base, 'crm');\n }\n\n public function flowCatalogForPrompt(string $channel): string\n {\n return app(ManuFlowPromptBuilder::class)->compactCatalogForPrompt($channel);\n }\n\n private function appendFlowCatalog(string $base, string $channel): string\n {\n if (! config('manu.flows_inject_into_prompts', true)) {\n return $base;\n }\n\n $catalog = $this->flowCatalogForPrompt($channel);\n\n if ($catalog === '') {\n return $base;\n }\n\n return trim($base.\"\\n\\n\".$catalog);\n }\n\n /**\n * @return array<int, string>\n */\n public function handoffKeywords(): array\n {\n $keywords = data_get($this->all(), 'handoff_keywords', config('manu.handoff_keywords', []));\n\n return collect($keywords)\n ->filter(fn ($item) => is_string($item) && trim($item) !== '')\n ->map(fn (string $item) => mb_strtolower(trim($item)))\n ->values()\n ->all();\n }\n\n /**\n * @return array{provider: string, model: ?string, api_key: ?string, temperature: float, max_steps: int}\n */\n public function aiConfigForChannel(string $channel): array\n {\n $settings = $this->all();\n $prefix = $channel === 'crm' ? 'crm' : 'whatsapp';\n\n $provider = (string) data_get($settings, \"ai.{$prefix}_provider\", data_get($settings, 'ai.default_provider', 'openai'));\n $model = data_get($settings, \"ai.{$prefix}_model\");\n $encryptedKey = data_get($settings, \"ai.{$prefix}_api_key\");\n\n return [\n 'provider' => $provider,\n 'model' => is_string($model) && $model !== '' ? $model : null,\n 'api_key' => $this->decryptApiKey($encryptedKey),\n 'temperature' => (float) data_get($settings, 'ai.temperature', 0.65),\n 'max_steps' => (int) data_get($settings, 'ai.max_steps', config('manu.max_tool_steps', 6)),\n ];\n }\n\n /**\n * @return array{provider: string, model: ?string, api_key: ?string}\n */\n public function trainingAiConfig(): array\n {\n $settings = $this->all();\n\n return [\n 'provider' => (string) data_get($settings, 'ai.training_provider', data_get($settings, 'ai.default_provider', 'openai')),\n 'model' => data_get($settings, 'ai.training_model') ?: null,\n 'api_key' => $this->decryptApiKey(data_get($settings, 'ai.training_api_key')),\n ];\n }\n\n /**\n * @return array<string, mixed>\n */\n public function forAdmin(): array\n {\n $settings = $this->all();\n\n foreach (['whatsapp_api_key', 'crm_api_key', 'training_api_key'] as $keyField) {\n if (filled(data_get($settings, \"ai.{$keyField}\"))) {\n data_set($settings, \"ai.{$keyField}\", '********');\n }\n }\n\n if (trim((string) data_get($settings, 'prompts.whatsapp', '')) === '') {\n data_set($settings, 'prompts.whatsapp', (string) config('manu.instructions', ''));\n }\n\n if (trim((string) data_get($settings, 'prompts.crm', '')) === '') {\n data_set($settings, 'prompts.crm', (string) config('manu.crm_instructions', ''));\n }\n\n if (empty(data_get($settings, 'handoff_keywords'))) {\n data_set($settings, 'handoff_keywords', config('manu.handoff_keywords', []));\n }\n\n return $settings;\n }\n\n /**\n * @return array<string, array<int, string>>\n */\n public function providerModels(): array\n {\n return [\n 'openai' => ['gpt-4o', 'gpt-4o-mini', 'gpt-4.1-mini', 'gpt-4.1'],\n 'anthropic' => ['claude-sonnet-4-20250514', 'claude-haiku-4-5-20251001', 'claude-3-5-haiku-latest'],\n 'gemini' => ['gemini-3.6-flash', 'gemini-3.5-flash', 'gemini-3.5-flash-lite', 'gemini-2.5-flash', 'gemini-2.5-pro'],\n 'deepseek' => ['deepseek-chat', 'deepseek-reasoner'],\n 'groq' => ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant'],\n 'openrouter' => ['openai/gpt-4o-mini', 'anthropic/claude-3.5-haiku', 'google/gemini-3.6-flash'],\n 'mistral' => ['mistral-large-latest', 'mistral-small-latest'],\n 'xai' => ['grok-2-latest'],\n ];\n }\n\n /**\n * @return array<int, array{value: string, label: string, env_key: string}>\n */\n public function providerOptions(): array\n {\n return [\n ['value' => 'openai', 'label' => 'OpenAI (GPT)', 'env_key' => 'OPENAI_API_KEY'],\n ['value' => 'anthropic', 'label' => 'Anthropic (Claude)', 'env_key' => 'ANTHROPIC_API_KEY'],\n ['value' => 'gemini', 'label' => 'Google Gemini', 'env_key' => 'GEMINI_API_KEY'],\n ['value' => 'deepseek', 'label' => 'DeepSeek', 'env_key' => 'DEEPSEEK_API_KEY'],\n ['value' => 'groq', 'label' => 'Groq', 'env_key' => 'GROQ_API_KEY'],\n ['value' => 'openrouter', 'label' => 'OpenRouter (multi-modelo)', 'env_key' => 'OPENROUTER_API_KEY'],\n ['value' => 'mistral', 'label' => 'Mistral', 'env_key' => 'MISTRAL_API_KEY'],\n ['value' => 'xai', 'label' => 'xAI (Grok)', 'env_key' => 'XAI_API_KEY'],\n ];\n }\n\n /**\n * @return array<string, mixed>\n */\n public function defaults(): array\n {\n return [\n 'prompts' => [\n 'whatsapp' => '',\n 'crm' => '',\n 'training_notes' => '',\n ],\n 'handoff_keywords' => config('manu.handoff_keywords', []),\n 'ai' => [\n 'default_provider' => config('ai.default', 'gemini'),\n 'whatsapp_provider' => config('ai.default', 'gemini'),\n 'whatsapp_model' => 'gemini-3.6-flash',\n 'whatsapp_api_key' => null,\n 'crm_provider' => config('ai.default', 'gemini'),\n 'crm_model' => 'gemini-3.6-flash',\n 'crm_api_key' => null,\n 'training_provider' => config('ai.default', 'gemini'),\n 'training_model' => 'gemini-3.6-flash',\n 'training_api_key' => null,\n 'temperature' => 0.65,\n 'max_steps' => (int) config('manu.max_tool_steps', 6),\n ],\n ];\n }\n\n private function decryptApiKey(mixed $encrypted): ?string\n {\n if (! is_string($encrypted) || $encrypted === '') {\n return null;\n }\n\n try {\n return Crypt::decryptString($encrypted);\n } catch (\\Throwable) {\n return null;\n }\n }\n}\n"}}}} |