Compare commits
10 Commits
382dc4aa03
...
925fbe0bd7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
925fbe0bd7 | ||
|
|
2683b6324f | ||
|
|
beae82a898 | ||
|
|
23f32b3cf1 | ||
|
|
382d0862b8 | ||
|
|
7bf5775ad9 | ||
|
|
a30cfb28a5 | ||
|
|
b0066ecc75 | ||
|
|
98c8c6fe02 | ||
|
|
2123cec88a |
@ -37,6 +37,7 @@ public function handle()
|
|||||||
'migrate:company' => '🏭 Migrating companies & partner media...',
|
'migrate:company' => '🏭 Migrating companies & partner media...',
|
||||||
'migrate:journalist' => '📰 Migrating journalists...',
|
'migrate:journalist' => '📰 Migrating journalists...',
|
||||||
'migrate:media-orders' => '📦 Migrating media orders...',
|
'migrate:media-orders' => '📦 Migrating media orders...',
|
||||||
|
'migrate:reports' => '📋 Migrating report proofs (bukti tayang)...',
|
||||||
'migrate:media-cooperation' => '🤝 Migrating media cooperation...',
|
'migrate:media-cooperation' => '🤝 Migrating media cooperation...',
|
||||||
'migrate:media-monitoring' => '🖥️ Migrating media monitoring...',
|
'migrate:media-monitoring' => '🖥️ Migrating media monitoring...',
|
||||||
'migrate:issue-management' => '⚠️ Migrating issue management...',
|
'migrate:issue-management' => '⚠️ Migrating issue management...',
|
||||||
|
|||||||
@ -381,6 +381,24 @@ private function processReport(object $legacyReport, int $cooperationId, int $ta
|
|||||||
|
|
||||||
[$cleanTitle, $cleanLink] = $this->extractLinkData($legacyReport);
|
[$cleanTitle, $cleanLink] = $this->extractLinkData($legacyReport);
|
||||||
|
|
||||||
|
$existingReportId = DB::table('reports')
|
||||||
|
->where('media_task_assignment_id', $mediaTaskAssignment->id)
|
||||||
|
->where('publication_date', $legacyReport->broadcast)
|
||||||
|
->where('link', $cleanLink)
|
||||||
|
->value('id');
|
||||||
|
|
||||||
|
if ($existingReportId) {
|
||||||
|
if (! isset($this->migratedReportIds[$existingReportId])) {
|
||||||
|
$report = Report::find($existingReportId);
|
||||||
|
if ($report) {
|
||||||
|
$this->migrateProof($report, $legacyReport);
|
||||||
|
$this->migratedReportIds[$existingReportId] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DB::table('reports')->insert([
|
DB::table('reports')->insert([
|
||||||
'media_task_assignment_id' => $mediaTaskAssignment->id,
|
'media_task_assignment_id' => $mediaTaskAssignment->id,
|
||||||
'title' => $cleanTitle,
|
'title' => $cleanTitle,
|
||||||
@ -394,13 +412,13 @@ private function processReport(object $legacyReport, int $cooperationId, int $ta
|
|||||||
|
|
||||||
$newReportId = (int) DB::getPdo()->lastInsertId();
|
$newReportId = (int) DB::getPdo()->lastInsertId();
|
||||||
|
|
||||||
// // Migrate proof image if not already done
|
if (! isset($this->migratedReportIds[$newReportId])) {
|
||||||
// if (! isset($this->migratedReportIds[$newReportId])) {
|
$report = Report::find($newReportId);
|
||||||
// $report = Report::find($newReportId);
|
if ($report) {
|
||||||
// if ($report) {
|
$this->migrateProof($report, $legacyReport);
|
||||||
// $this->migrateProof($report, $legacyReport);
|
$this->migratedReportIds[$newReportId] = true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -134,12 +134,26 @@ private function processReport(object $legacy): void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the report
|
[$cleanTitle, $cleanLink] = $this->extractLinkData($legacy);
|
||||||
|
|
||||||
|
$existing = DB::table('reports')
|
||||||
|
->where('media_task_assignment_id', $mediaTaskAssignment->id)
|
||||||
|
->where('publication_date', $legacy->broadcast)
|
||||||
|
->where('link', $cleanLink)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($existing) {
|
||||||
|
$proofMigrated = $this->migrateProofIfNeeded($existing->id, $legacy);
|
||||||
|
$this->output->writeln($proofMigrated ? '<info>SKIP + IMG</info>' : '<info>SKIP</info>');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DB::table('reports')->insert([
|
DB::table('reports')->insert([
|
||||||
'media_task_assignment_id' => $mediaTaskAssignment->id,
|
'media_task_assignment_id' => $mediaTaskAssignment->id,
|
||||||
'title' => $legacy->title ?? '',
|
'title' => $cleanTitle,
|
||||||
'publication_date' => $legacy->broadcast,
|
'publication_date' => $legacy->broadcast,
|
||||||
'link' => $legacy->link ?? '',
|
'link' => $cleanLink,
|
||||||
'description' => '',
|
'description' => '',
|
||||||
'status' => $this->mapApprovalStatus((string) $legacy->status),
|
'status' => $this->mapApprovalStatus((string) $legacy->status),
|
||||||
'created_at' => $legacy->created_at ?? now(),
|
'created_at' => $legacy->created_at ?? now(),
|
||||||
@ -148,32 +162,46 @@ private function processReport(object $legacy): void
|
|||||||
|
|
||||||
$newReportId = (int) DB::getPdo()->lastInsertId();
|
$newReportId = (int) DB::getPdo()->lastInsertId();
|
||||||
|
|
||||||
// Migrate proof image if not already done
|
$proofMigrated = $this->migrateProofIfNeeded($newReportId, $legacy);
|
||||||
if (! isset($this->migratedIds[$newReportId])) {
|
|
||||||
$report = Report::find($newReportId);
|
|
||||||
if ($report) {
|
|
||||||
$this->migrateProof($report, $legacy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->output->writeln('<info>DONE</info>');
|
$this->output->writeln($proofMigrated ? '<info>DONE + IMG</info>' : '<info>DONE</info>');
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->output->writeln('<error>FAILED: '.$e->getMessage().'</error>');
|
$this->output->writeln('<error>FAILED: '.$e->getMessage().'</error>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate the proof image file from S3 to the Report media library.
|
* Register proof media for a report when not yet migrated.
|
||||||
*/
|
*/
|
||||||
private function migrateProof(Report $report, object $legacy): void
|
private function migrateProofIfNeeded(int $reportId, object $legacy): bool
|
||||||
|
{
|
||||||
|
if (isset($this->migratedIds[$reportId])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$report = Report::find($reportId);
|
||||||
|
if (! $report) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->migrateProof($report, $legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate the proof image metadata (file stays on S3 legacy path).
|
||||||
|
*/
|
||||||
|
private function migrateProof(Report $report, object $legacy): bool
|
||||||
{
|
{
|
||||||
$legacyPath = trim($legacy->proof ?? '');
|
$legacyPath = trim($legacy->proof ?? '');
|
||||||
if (empty($legacyPath) || $legacyPath === '-' || $legacyPath === 'no-image.png') {
|
if (empty($legacyPath) || $legacyPath === '-' || $legacyPath === 'no-image.png') {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$sourcePath = 'old-data/reports/'.$legacyPath;
|
$sourcePath = 'old-data/reports/'.$legacyPath;
|
||||||
$this->importProofFile($report, $sourcePath, $legacy);
|
$this->importProofFile($report, $sourcePath, $legacy);
|
||||||
|
$this->migratedIds[$report->id] = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -222,6 +250,45 @@ private function guessMime(string $fileName): string
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ekstrak title & link bersih dari legacy report.
|
||||||
|
*
|
||||||
|
* @return array{0: string, 1: string} [title, link]
|
||||||
|
*/
|
||||||
|
private function extractLinkData(object $legacyReport): array
|
||||||
|
{
|
||||||
|
$rawTitle = trim($legacyReport->title ?? '');
|
||||||
|
$rawLink = trim($legacyReport->link ?? '');
|
||||||
|
|
||||||
|
$titleIsUrl = (bool) preg_match('#^https?://#i', $rawTitle);
|
||||||
|
|
||||||
|
preg_match('#https?://\S+#', $rawLink, $urlMatches);
|
||||||
|
$extractedUrl = rtrim($urlMatches[0] ?? '', '.,;)');
|
||||||
|
|
||||||
|
if ($titleIsUrl) {
|
||||||
|
$cleanLink = $rawTitle;
|
||||||
|
|
||||||
|
$lines = array_values(array_filter(
|
||||||
|
array_map('trim', preg_split('/[\r\n]+/', $rawLink))
|
||||||
|
));
|
||||||
|
$candidateTitle = '';
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
if (! preg_match('#^https?://#i', $line)) {
|
||||||
|
$candidateTitle = $line;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$cleanTitle = $candidateTitle !== ''
|
||||||
|
? mb_substr($candidateTitle, 0, 255)
|
||||||
|
: mb_substr($rawTitle, 0, 255);
|
||||||
|
} else {
|
||||||
|
$cleanLink = $extractedUrl ?: mb_substr($rawLink, 0, 2048);
|
||||||
|
$cleanTitle = mb_substr($rawTitle, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$cleanTitle, $cleanLink];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map legacy reports.status integer to ApprovalStatus enum value.
|
* Map legacy reports.status integer to ApprovalStatus enum value.
|
||||||
* Legacy: 0 = menunggu, 1 = menerima, 2 = menolak
|
* Legacy: 0 = menunggu, 1 = menerima, 2 = menolak
|
||||||
|
|||||||
@ -156,7 +156,8 @@ public function form(Schema $schema): Schema
|
|||||||
'indigo' => '🌌 Indigo (Ungu Gelap)',
|
'indigo' => '🌌 Indigo (Ungu Gelap)',
|
||||||
])
|
])
|
||||||
->placeholder('Pilih warna tema')
|
->placeholder('Pilih warna tema')
|
||||||
->native(false),
|
->native(false)
|
||||||
|
->required(),
|
||||||
|
|
||||||
Select::make('settings.font')
|
Select::make('settings.font')
|
||||||
->label('Jenis Huruf (Font)')
|
->label('Jenis Huruf (Font)')
|
||||||
@ -168,7 +169,8 @@ public function form(Schema $schema): Schema
|
|||||||
'Montserrat' => 'Montserrat (Classic)',
|
'Montserrat' => 'Montserrat (Classic)',
|
||||||
'Lexend' => 'Lexend (Readable)',
|
'Lexend' => 'Lexend (Readable)',
|
||||||
])
|
])
|
||||||
->native(false),
|
->native(false)
|
||||||
|
->required(),
|
||||||
|
|
||||||
Select::make('settings.content_width')
|
Select::make('settings.content_width')
|
||||||
->label('Lebar Konten')
|
->label('Lebar Konten')
|
||||||
@ -176,7 +178,8 @@ public function form(Schema $schema): Schema
|
|||||||
'full' => '↔️ Lebar Penuh (Full)',
|
'full' => '↔️ Lebar Penuh (Full)',
|
||||||
'centered' => '🏢 Terpusat (Centered)',
|
'centered' => '🏢 Terpusat (Centered)',
|
||||||
])
|
])
|
||||||
->native(false),
|
->native(false)
|
||||||
|
->required(),
|
||||||
|
|
||||||
Select::make('settings.border_radius')
|
Select::make('settings.border_radius')
|
||||||
->label('Radius Sudut (Border)')
|
->label('Radius Sudut (Border)')
|
||||||
@ -186,7 +189,8 @@ public function form(Schema $schema): Schema
|
|||||||
'lg' => '🎉 Rounded (Cheerful)',
|
'lg' => '🎉 Rounded (Cheerful)',
|
||||||
'xl' => '🎈 Extra Round',
|
'xl' => '🎈 Extra Round',
|
||||||
])
|
])
|
||||||
->native(false),
|
->native(false)
|
||||||
|
->required(),
|
||||||
|
|
||||||
Toggle::make('settings.top_navigation')
|
Toggle::make('settings.top_navigation')
|
||||||
->label('Navigasi Atas (Top Nav)')
|
->label('Navigasi Atas (Top Nav)')
|
||||||
|
|||||||
@ -3,14 +3,18 @@
|
|||||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
||||||
|
|
||||||
use App\Enums\RoleEnum;
|
use App\Enums\RoleEnum;
|
||||||
|
use App\Filament\Support\MediaDataUri;
|
||||||
use App\Settings\GeneralSettings;
|
use App\Settings\GeneralSettings;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
use Filament\Actions\Action;
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Notifications\Notification;
|
||||||
use Filament\Tables\Table;
|
use Filament\Tables\Table;
|
||||||
use Illuminate\Support\Facades\Blade;
|
use Illuminate\Support\Facades\Blade;
|
||||||
|
|
||||||
class ExportAllReportsPdfAction extends Action
|
class ExportAllReportsPdfAction extends Action
|
||||||
{
|
{
|
||||||
|
private const MAX_RECORDS = 500;
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
{
|
{
|
||||||
return 'export_all_pdf';
|
return 'export_all_pdf';
|
||||||
@ -24,29 +28,43 @@ protected function setUp(): void
|
|||||||
->color('info')
|
->color('info')
|
||||||
->icon('heroicon-o-arrow-down-tray')
|
->icon('heroicon-o-arrow-down-tray')
|
||||||
->action(function (Table $table) {
|
->action(function (Table $table) {
|
||||||
$settings = app(GeneralSettings::class);
|
$query = $table->getLivewire()->getFilteredTableQuery();
|
||||||
$records = $table->getLivewire()->getFilteredTableQuery()->get();
|
$count = (clone $query)->count();
|
||||||
|
|
||||||
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
if ($count > self::MAX_RECORDS) {
|
||||||
$logoBase64 = null;
|
Notification::make()
|
||||||
if ($logoPath && file_exists($logoPath)) {
|
->title('Data terlalu banyak')
|
||||||
$logoData = base64_encode(file_get_contents($logoPath));
|
->body('Maksimal '.self::MAX_RECORDS.' laporan per unduhan. Gunakan filter tabel untuk mempersempit data.')
|
||||||
$logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData;
|
->warning()
|
||||||
|
->send();
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$records->each(function ($record) {
|
$settings = app(GeneralSettings::class);
|
||||||
$image = $record->getFirstMedia('reports');
|
|
||||||
$record->imageBase64 = null;
|
$records = $query
|
||||||
if ($image) {
|
->with([
|
||||||
$imagePath = $image->getPath();
|
'mediaTaskAssignment.partnerMedia',
|
||||||
if (file_exists($imagePath)) {
|
'media',
|
||||||
$imageData = base64_encode(file_get_contents($imagePath));
|
])
|
||||||
$record->imageBase64 = 'data:image/'.pathinfo($imagePath, PATHINFO_EXTENSION).';base64,'.$imageData;
|
->get();
|
||||||
}
|
|
||||||
}
|
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
||||||
});
|
$logoBase64 = MediaDataUri::fromPath($logoPath, maxWidth: 60, maxHeight: 60);
|
||||||
|
|
||||||
|
foreach ($records as $record) {
|
||||||
|
$record->imageBase64 = MediaDataUri::thumbnailForPdf(
|
||||||
|
$record->getFirstMedia('reports'),
|
||||||
|
maxWidth: 150,
|
||||||
|
maxHeight: 80,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($records, $settings, $logoBase64) {
|
return response()->streamDownload(function () use ($records, $settings, $logoBase64) {
|
||||||
|
@ini_set('memory_limit', '512M');
|
||||||
|
set_time_limit(120);
|
||||||
|
|
||||||
echo Pdf::loadHtml(
|
echo Pdf::loadHtml(
|
||||||
Blade::render('filament.manage.reports.print-all', [
|
Blade::render('filament.manage.reports.print-all', [
|
||||||
'records' => $records,
|
'records' => $records,
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
namespace App\Filament\Resources\Manage\Cooperations\Actions\Report;
|
||||||
|
|
||||||
use App\Enums\RoleEnum;
|
use App\Enums\RoleEnum;
|
||||||
|
use App\Filament\Support\MediaDataUri;
|
||||||
use App\Models\Report;
|
use App\Models\Report;
|
||||||
use App\Settings\GeneralSettings;
|
use App\Settings\GeneralSettings;
|
||||||
use Barryvdh\DomPDF\Facade\Pdf;
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
@ -27,24 +28,17 @@ protected function setUp(): void
|
|||||||
$settings = app(GeneralSettings::class);
|
$settings = app(GeneralSettings::class);
|
||||||
|
|
||||||
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
$logoPath = $settings->site_icon ? storage_path('app/public/'.$settings->site_icon) : null;
|
||||||
|
$logoBase64 = MediaDataUri::fromPath($logoPath, maxWidth: 80, maxHeight: 100);
|
||||||
|
|
||||||
$logoBase64 = null;
|
$imageBase64 = MediaDataUri::thumbnailForPdf(
|
||||||
if ($logoPath && file_exists($logoPath)) {
|
$record->getFirstMedia('reports'),
|
||||||
$logoData = base64_encode(file_get_contents($logoPath));
|
maxWidth: 800,
|
||||||
$logoBase64 = 'data:image/'.pathinfo($logoPath, PATHINFO_EXTENSION).';base64,'.$logoData;
|
maxHeight: 400,
|
||||||
}
|
);
|
||||||
|
|
||||||
$image = $record->getFirstMedia('reports');
|
|
||||||
$imageBase64 = null;
|
|
||||||
if ($image) {
|
|
||||||
$imagePath = $image->getPath();
|
|
||||||
if (file_exists($imagePath)) {
|
|
||||||
$imageData = base64_encode(file_get_contents($imagePath));
|
|
||||||
$imageBase64 = 'data:image/'.pathinfo($imagePath, PATHINFO_EXTENSION).';base64,'.$imageData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->streamDownload(function () use ($record, $settings, $logoBase64, $imageBase64) {
|
return response()->streamDownload(function () use ($record, $settings, $logoBase64, $imageBase64) {
|
||||||
|
set_time_limit(60);
|
||||||
|
|
||||||
echo Pdf::loadHtml(
|
echo Pdf::loadHtml(
|
||||||
Blade::render('filament.manage.reports.print', [
|
Blade::render('filament.manage.reports.print', [
|
||||||
'record' => $record,
|
'record' => $record,
|
||||||
|
|||||||
@ -45,7 +45,6 @@ public static function configure(Schema $schema): Schema
|
|||||||
->native(false)
|
->native(false)
|
||||||
->displayFormat('l, d F Y')
|
->displayFormat('l, d F Y')
|
||||||
->required()
|
->required()
|
||||||
->minDate(fn ($context) => $context === 'create' ? today() : null)
|
|
||||||
->reactive(),
|
->reactive(),
|
||||||
|
|
||||||
DatePicker::make('final_submission_date')
|
DatePicker::make('final_submission_date')
|
||||||
|
|||||||
@ -46,8 +46,7 @@ public static function configure(Schema $schema): Schema
|
|||||||
->label('Penulis')
|
->label('Penulis')
|
||||||
->placeholder('John Doe')
|
->placeholder('John Doe')
|
||||||
->autocomplete(false)
|
->autocomplete(false)
|
||||||
->required()
|
->required(),
|
||||||
->maxLength(50),
|
|
||||||
|
|
||||||
TextInput::make('link')
|
TextInput::make('link')
|
||||||
->label('Tautan (URL)')
|
->label('Tautan (URL)')
|
||||||
|
|||||||
@ -58,6 +58,7 @@ public static function configure(Table $table): Table
|
|||||||
|
|
||||||
TextColumn::make('writter')
|
TextColumn::make('writter')
|
||||||
->label('Penulis')
|
->label('Penulis')
|
||||||
|
->limit(30)
|
||||||
->searchable()
|
->searchable()
|
||||||
->sortable(),
|
->sortable(),
|
||||||
|
|
||||||
|
|||||||
127
app/Filament/Support/MediaDataUri.php
Normal file
127
app/Filament/Support/MediaDataUri.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Support;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||||
|
|
||||||
|
class MediaDataUri
|
||||||
|
{
|
||||||
|
public static function fromMedia(?Media $media): ?string
|
||||||
|
{
|
||||||
|
if (! $media) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disk = Storage::disk($media->disk);
|
||||||
|
$path = $media->getPathRelativeToRoot();
|
||||||
|
|
||||||
|
if (! $disk->exists($path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mime = $media->mime_type ?: 'application/octet-stream';
|
||||||
|
|
||||||
|
return 'data:'.$mime.';base64,'.base64_encode($disk->get($path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromPath(?string $absolutePath, int $maxWidth = 80, int $maxHeight = 80): ?string
|
||||||
|
{
|
||||||
|
if (! $absolutePath || ! file_exists($absolutePath)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = file_get_contents($absolutePath);
|
||||||
|
|
||||||
|
if ($contents === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::encodeResizedImage($contents, $maxWidth, $maxHeight)
|
||||||
|
?? self::encodeRawFile($absolutePath, $contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function thumbnailForPdf(?Media $media, int $maxWidth = 150, int $maxHeight = 80): ?string
|
||||||
|
{
|
||||||
|
if (! $media) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$disk = Storage::disk($media->disk);
|
||||||
|
$path = $media->getPathRelativeToRoot();
|
||||||
|
|
||||||
|
if (! $disk->exists($path)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mime = $media->mime_type ?? '';
|
||||||
|
|
||||||
|
if (! str_starts_with($mime, 'image/')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$contents = $disk->get($path);
|
||||||
|
|
||||||
|
return self::encodeResizedImage($contents, $maxWidth, $maxHeight)
|
||||||
|
?? self::fromMedia($media);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function encodeResizedImage(string $contents, int $maxWidth, int $maxHeight): ?string
|
||||||
|
{
|
||||||
|
if (! extension_loaded('gd')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$image = @imagecreatefromstring($contents);
|
||||||
|
|
||||||
|
if ($image === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$width = imagesx($image);
|
||||||
|
$height = imagesy($image);
|
||||||
|
$ratio = min($maxWidth / $width, $maxHeight / $height, 1);
|
||||||
|
$newWidth = max(1, (int) round($width * $ratio));
|
||||||
|
$newHeight = max(1, (int) round($height * $ratio));
|
||||||
|
|
||||||
|
$thumb = imagecreatetruecolor($newWidth, $newHeight);
|
||||||
|
|
||||||
|
if ($thumb === false) {
|
||||||
|
imagedestroy($image);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
imagecopyresampled($thumb, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||||
|
imagedestroy($image);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
imagejpeg($thumb, quality: 75);
|
||||||
|
imagedestroy($thumb);
|
||||||
|
$jpeg = ob_get_clean();
|
||||||
|
|
||||||
|
if ($jpeg === false || $jpeg === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'data:image/jpeg;base64,'.base64_encode($jpeg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function encodeRawFile(string $absolutePath, string $contents): ?string
|
||||||
|
{
|
||||||
|
$extension = strtolower(pathinfo($absolutePath, PATHINFO_EXTENSION));
|
||||||
|
$mime = match ($extension) {
|
||||||
|
'png' => 'image/png',
|
||||||
|
'jpg', 'jpeg' => 'image/jpeg',
|
||||||
|
'gif' => 'image/gif',
|
||||||
|
'webp' => 'image/webp',
|
||||||
|
default => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($mime === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'data:'.$mime.';base64,'.base64_encode($contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('media_monitorings', function (Blueprint $table) {
|
||||||
|
$table->text('writter')->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('media_monitorings', function (Blueprint $table) {
|
||||||
|
$table->string('writter', 50)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -3,4 +3,4 @@
|
|||||||
use Illuminate\Support\Facades\Schedule;
|
use Illuminate\Support\Facades\Schedule;
|
||||||
|
|
||||||
Schedule::command('cooperation:update-status')->daily();
|
Schedule::command('cooperation:update-status')->daily();
|
||||||
Schedule::command('monitoring:crawl')->dailyAt('12:00');
|
Schedule::command('monitoring:crawl')->daily();
|
||||||
|
|||||||
@ -20,12 +20,13 @@
|
|||||||
expect(CooperationStatus::options())->toEqual([
|
expect(CooperationStatus::options())->toEqual([
|
||||||
1 => 'Menunggu',
|
1 => 'Menunggu',
|
||||||
2 => 'Media Order',
|
2 => 'Media Order',
|
||||||
4 => 'Pembayaran',
|
3 => 'Pembayaran',
|
||||||
5 => 'Selesai',
|
4 => 'Selesai',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('cooperation status enum values and comment', function () {
|
test('cooperation status enum values and comment', function () {
|
||||||
expect(CooperationStatus::values())->toEqual([1, 2, 4, 5]);
|
expect(CooperationStatus::values())->toEqual([1, 2, 3, 4]);
|
||||||
expect(CooperationStatus::comment())->toBe('1: Menunggu, 2: Media Order, 4: Pembayaran, 5: Selesai');
|
expect(CooperationStatus::comment())->toBe('1: Menunggu, 2: Media Order, 3: Pembayaran, 4: Selesai');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user