diff --git a/app/Console/UnlockPdf.php b/app/Console/UnlockPdf.php new file mode 100644 index 0000000..a9822d9 --- /dev/null +++ b/app/Console/UnlockPdf.php @@ -0,0 +1,49 @@ +argument('directory'); + $password = $this->option('password'); + + $this->info('Starting PDF unlock process...'); + + // Dispatch the job + UnlockPdfJob::dispatch($directory, $password); + + $this->info('PDF unlock job has been queued.'); + + return 0; + } catch (Exception $e) { + $this->error('Error processing PDF unlock: ' . $e->getMessage()); + return 1; + } + } +} diff --git a/app/Jobs/UnlockPdfJob.php b/app/Jobs/UnlockPdfJob.php new file mode 100644 index 0000000..62dc68d --- /dev/null +++ b/app/Jobs/UnlockPdfJob.php @@ -0,0 +1,135 @@ +baseDirectory = $baseDirectory; + $this->password = $password; + } + + /** + * Execute the job. + */ + public function handle(): void + { + try { + Log::info("Starting PDF unlock process in directory: {$this->baseDirectory}"); + + // Check if directory exists + if (!File::isDirectory($this->baseDirectory)) { + Log::error("Directory not found: {$this->baseDirectory}"); + return; + } + + // Get all subdirectories (year folders like 202505) + $yearDirectories = File::directories($this->baseDirectory); + + foreach ($yearDirectories as $yearDirectory) { + $this->processYearDirectory($yearDirectory); + } + + Log::info("PDF unlock process completed successfully."); + } catch (Exception $e) { + Log::error("Error unlocking PDF files: " . $e->getMessage()); + } + } + + /** + * Process a year directory (e.g., 202505) + * + * @param string $yearDirectory Directory path to process + */ + protected function processYearDirectory(string $yearDirectory): void + { + try { + // Get all ID directories (e.g., ID0010001) + $idDirectories = File::directories($yearDirectory); + + foreach ($idDirectories as $idDirectory) { + $this->processIdDirectory($idDirectory); + } + } catch (Exception $e) { + Log::error("Error processing year directory {$yearDirectory}: " . $e->getMessage()); + } + } + + /** + * Process an ID directory (e.g., ID0010001) + * + * @param string $idDirectory Directory path to process + */ + protected function processIdDirectory(string $idDirectory): void + { + try { + // Get all PDF files in the directory + $pdfFiles = File::glob($idDirectory . '/*.pdf'); + + foreach ($pdfFiles as $pdfFile) { + $this->unlockPdf($pdfFile); + } + } catch (Exception $e) { + Log::error("Error processing ID directory {$idDirectory}: " . $e->getMessage()); + } + } + + /** + * Unlock a password-protected PDF file + * + * @param string $pdfFilePath Path to PDF file + */ + protected function unlockPdf(string $pdfFilePath): void + { + try { + $filename = pathinfo($pdfFilePath, PATHINFO_FILENAME); + $directory = pathinfo($pdfFilePath, PATHINFO_DIRNAME); + $decryptedPdfPath = $directory . '/' . $filename . '.dec.pdf'; + + // Skip if the decrypted file already exists + if (File::exists($decryptedPdfPath)) { + Log::info("Decrypted file already exists: {$decryptedPdfPath}"); + return; + } + + // Create qpdf command + $command = ['qpdf', '--password=' . $this->password, '--decrypt', $pdfFilePath, $decryptedPdfPath]; + + // Execute the command + $process = new Process($command); + $process->run(); + + // Check if the command was successful + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + + Log::info("Unlocked PDF: {$pdfFilePath} to {$decryptedPdfPath}"); + } catch (Exception $e) { + Log::error("Error unlocking PDF {$pdfFilePath}: " . $e->getMessage()); + } + } +} diff --git a/app/Providers/WebstatementServiceProvider.php b/app/Providers/WebstatementServiceProvider.php index 6f0054e..261cac3 100644 --- a/app/Providers/WebstatementServiceProvider.php +++ b/app/Providers/WebstatementServiceProvider.php @@ -13,6 +13,7 @@ use Modules\Webstatement\Console\ProcessDailyMigration; use Modules\Webstatement\Console\GenerateBiayakartuCommand; use Modules\Webstatement\Jobs\UpdateAtmCardBranchCurrencyJob; use Modules\Webstatement\Console\GenerateBiayaKartuCsvCommand; +use Modules\Webstatement\Console\UnlockPdf; class WebstatementServiceProvider extends ServiceProvider { @@ -60,7 +61,8 @@ class WebstatementServiceProvider extends ServiceProvider ProcessDailyMigration::class, ExportDailyStatements::class, CombinePdf::class, - ConvertHtmlToPdf::class + ConvertHtmlToPdf::class, + UnlockPdf::class, ]); } @@ -112,6 +114,12 @@ class WebstatementServiceProvider extends ServiceProvider ->dailyAt('09:30') ->withoutOverlapping() ->appendOutputTo(storage_path('logs/convert-html-to-pdf.log')); + + // Unlock PDF + $schedule->command('webstatement:unlock-pdf') + ->dailyAt('09:30') + ->withoutOverlapping() + ->appendOutputTo(storage_path('logs/unlock-pdf.log')); } /**