tennant/onticket #9
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
use Database\Seeders\OptimizeOnticketImagesSeeder;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (app()->environment('testing')) {
|
||||
Storage::fake('s3');
|
||||
}
|
||||
|
||||
app(OptimizeOnticketImagesSeeder::class)->run();
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// The optimized attachments may already be in active use. Keep this
|
||||
// data migration irreversible instead of restoring heavier assets.
|
||||
}
|
||||
};
|
||||
|
|
@ -14,6 +14,8 @@ use RuntimeException;
|
|||
|
||||
class OnTicketTenantSeeder extends Seeder
|
||||
{
|
||||
private const IMAGE_DIRECTORY = 'images/tennants/onticket_otpimizado';
|
||||
|
||||
public function __construct(
|
||||
private readonly TenantProvisioningService $tenantProvisioningService,
|
||||
private readonly WebsiteExtraService $websiteExtraService,
|
||||
|
|
@ -49,7 +51,7 @@ class OnTicketTenantSeeder extends Seeder
|
|||
'header_logo' => $this->uploadedImage('onticket_logo.png'),
|
||||
'footer_logo' => $this->uploadedImage('onticket_footer_logo.png'),
|
||||
'favicon' => $this->uploadedImage('onticket_favicon.svg'),
|
||||
'header_bg_image' => $this->uploadedImage('onticket_header_background.png'),
|
||||
'header_bg_image' => $this->uploadedImage('onticket_header_background.avif'),
|
||||
]);
|
||||
} else {
|
||||
$tenant->update([
|
||||
|
|
@ -64,7 +66,7 @@ class OnTicketTenantSeeder extends Seeder
|
|||
'header_logo' => ['relation' => 'headerLogo', 'filename' => 'onticket_logo.png'],
|
||||
'footer_logo' => ['relation' => 'footerLogo', 'filename' => 'onticket_footer_logo.png'],
|
||||
'favicon' => ['relation' => 'favicon', 'filename' => 'onticket_favicon.svg'],
|
||||
'header_bg_image' => ['relation' => 'headerBackgroundImage', 'filename' => 'onticket_header_background.png'],
|
||||
'header_bg_image' => ['relation' => 'headerBackgroundImage', 'filename' => 'onticket_header_background.avif'],
|
||||
] as $field => $image) {
|
||||
$attachment = $tenant->{$image['relation']};
|
||||
|
||||
|
|
@ -98,7 +100,7 @@ class OnTicketTenantSeeder extends Seeder
|
|||
|
||||
private function uploadedImage(string $filename): UploadedFile
|
||||
{
|
||||
$path = public_path("images/tennants/onticket/{$filename}");
|
||||
$path = public_path(self::IMAGE_DIRECTORY."/{$filename}");
|
||||
|
||||
if (! is_file($path)) {
|
||||
throw new RuntimeException("Image not found at path: {$path}");
|
||||
|
|
@ -106,6 +108,7 @@ class OnTicketTenantSeeder extends Seeder
|
|||
|
||||
$mimeType = match (strtolower(pathinfo($filename, PATHINFO_EXTENSION))) {
|
||||
'svg' => 'image/svg+xml',
|
||||
'avif' => 'image/avif',
|
||||
default => 'image/png',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ use RuntimeException;
|
|||
|
||||
class OnticketImmersiveHeroCarouselSeeder extends Seeder
|
||||
{
|
||||
private const IMAGE_DIRECTORY = 'images/tennants/onticket_otpimizado/onticket_tennant_hero_carousel';
|
||||
|
||||
private const IMAGES = [
|
||||
'onticket_hero_carousel_1.png',
|
||||
'onticket_hero_carousel_2.png',
|
||||
'onticket_hero_carousel_1.avif',
|
||||
'onticket_hero_carousel_2.avif',
|
||||
'onticket_hero_carousel_3.avif',
|
||||
'onticket_hero_carousel_4.jfif',
|
||||
'onticket_hero_carousel_5.jfif',
|
||||
'onticket_hero_carousel_6.jfif',
|
||||
'onticket_hero_carousel_4.avif',
|
||||
'onticket_hero_carousel_5.avif',
|
||||
'onticket_hero_carousel_6.avif',
|
||||
'onticket_hero_carousel_7.avif',
|
||||
'onticket_hero_carousel_8.avif',
|
||||
];
|
||||
|
|
@ -39,7 +41,7 @@ class OnticketImmersiveHeroCarouselSeeder extends Seeder
|
|||
}
|
||||
|
||||
$images = array_map(function (string $filename): UploadedFile {
|
||||
$path = public_path("images/tennants/onticket/onticket_tennant_hero_carousel/{$filename}");
|
||||
$path = public_path(self::IMAGE_DIRECTORY."/{$filename}");
|
||||
|
||||
if (! is_file($path)) {
|
||||
throw new RuntimeException("Image not found at path: {$path}");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Shared\Attachable\Models\Attachment;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
class OptimizeOnticketImagesSeeder extends Seeder
|
||||
{
|
||||
private const IMAGE_DIRECTORY = 'images/tennants/onticket_otpimizado';
|
||||
|
||||
private const CAROUSEL_IMAGES = [
|
||||
'onticket_hero_carousel_1.avif',
|
||||
'onticket_hero_carousel_2.avif',
|
||||
'onticket_hero_carousel_3.avif',
|
||||
'onticket_hero_carousel_4.avif',
|
||||
'onticket_hero_carousel_5.avif',
|
||||
'onticket_hero_carousel_6.avif',
|
||||
'onticket_hero_carousel_7.avif',
|
||||
'onticket_hero_carousel_8.avif',
|
||||
];
|
||||
|
||||
private const EVENT_IMAGES = [
|
||||
'[Prueba] Noche de Música en Vivo' => 'live-music.avif',
|
||||
'[Prueba] Festival de Sabores' => 'food-festival.avif',
|
||||
'[Prueba] Stand Up en el Centro' => 'stand-up.avif',
|
||||
];
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$tenant = Tenant::query()->where('codigo', 'onticket')->first();
|
||||
|
||||
if ($tenant === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->replaceAttachment(
|
||||
$tenant->headerBackgroundImage,
|
||||
'onticket_header_background.avif',
|
||||
);
|
||||
|
||||
$carousel = $tenant->websiteExtras()
|
||||
->whereHas(
|
||||
'websiteTypeExtra',
|
||||
fn ($query) => $query->where('codigo', 'immersiveHeroCarousel')
|
||||
)
|
||||
->first();
|
||||
$carouselIds = is_array($carousel?->config) ? array_values($carousel->config) : [];
|
||||
|
||||
foreach (self::CAROUSEL_IMAGES as $index => $filename) {
|
||||
$attachmentId = $carouselIds[$index] ?? null;
|
||||
|
||||
if (is_int($attachmentId)) {
|
||||
$this->replaceAttachment(
|
||||
Attachment::query()->find($attachmentId),
|
||||
'onticket_tennant_hero_carousel/'.$filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (self::EVENT_IMAGES as $title => $filename) {
|
||||
$event = $tenant->events()->where('title', $title)->first();
|
||||
|
||||
$this->replaceAttachment(
|
||||
$event?->attachment,
|
||||
'test-events/'.$filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function replaceAttachment(?Attachment $attachment, string $relativePath): void
|
||||
{
|
||||
if ($attachment === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sourcePath = public_path(self::IMAGE_DIRECTORY.'/'.$relativePath);
|
||||
|
||||
if (! is_file($sourcePath)) {
|
||||
throw new RuntimeException("Image not found at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$contents = file_get_contents($sourcePath);
|
||||
|
||||
if (! is_string($contents) || $contents === '') {
|
||||
throw new RuntimeException("Could not read image at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$filename = basename($relativePath);
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
$mimeType = match ($extension) {
|
||||
'avif' => 'image/avif',
|
||||
'svg' => 'image/svg+xml',
|
||||
default => 'image/png',
|
||||
};
|
||||
$directory = trim(str_replace('\\', '/', dirname($attachment->path)), './');
|
||||
$storedFilename = $attachment->key.($extension === '' ? '' : '.'.$extension);
|
||||
$newPath = $directory === '' ? $storedFilename : $directory.'/'.$storedFilename;
|
||||
$disk = Storage::disk('s3');
|
||||
|
||||
if (
|
||||
$attachment->path === $newPath
|
||||
&& $attachment->filename === $filename
|
||||
&& $attachment->mime_type === $mimeType
|
||||
&& $attachment->size === strlen($contents)
|
||||
&& $disk->exists($newPath)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oldPath = $attachment->path;
|
||||
$oldContents = $disk->exists($oldPath) ? $disk->get($oldPath) : null;
|
||||
|
||||
if (! $disk->put($newPath, $contents)) {
|
||||
throw new RuntimeException("Could not store optimized image at path: {$newPath}");
|
||||
}
|
||||
|
||||
try {
|
||||
DB::transaction(function () use (
|
||||
$attachment,
|
||||
$extension,
|
||||
$filename,
|
||||
$mimeType,
|
||||
$newPath,
|
||||
$contents,
|
||||
): void {
|
||||
$attachment->update([
|
||||
'path' => $newPath,
|
||||
'filename' => $filename,
|
||||
'type' => 'image',
|
||||
'mime_type' => $mimeType,
|
||||
'extension' => $extension,
|
||||
'size' => strlen($contents),
|
||||
]);
|
||||
});
|
||||
} catch (Throwable $throwable) {
|
||||
if ($newPath === $oldPath && is_string($oldContents)) {
|
||||
$disk->put($oldPath, $oldContents);
|
||||
} else {
|
||||
$disk->delete($newPath);
|
||||
}
|
||||
|
||||
throw $throwable;
|
||||
}
|
||||
|
||||
if ($oldPath !== $newPath && $disk->exists($oldPath)) {
|
||||
$disk->delete($oldPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,8 @@ use RuntimeException;
|
|||
|
||||
class TestEventsSeeder extends Seeder
|
||||
{
|
||||
private const IMAGE_DIRECTORY = 'images/tennants/onticket_otpimizado/test-events';
|
||||
|
||||
public function __construct(private readonly AttachmentService $attachmentService) {}
|
||||
|
||||
public function run(): void
|
||||
|
|
@ -24,7 +26,7 @@ class TestEventsSeeder extends Seeder
|
|||
'subtitle' => 'Una noche para cantar y bailar',
|
||||
'description' => 'Evento de prueba para explorar la cartelera de OnTicket.',
|
||||
'location' => 'Teatro Broadway, Rosario',
|
||||
'image' => 'live-music.png',
|
||||
'image' => 'live-music.avif',
|
||||
'weeks_from_now' => [2],
|
||||
'time_start' => '21:00:00',
|
||||
'time_end' => '23:30:00',
|
||||
|
|
@ -35,7 +37,7 @@ class TestEventsSeeder extends Seeder
|
|||
'subtitle' => 'Gastronomía y música para toda la familia',
|
||||
'description' => 'Evento de prueba con dos jornadas disponibles.',
|
||||
'location' => 'Parque de España, Rosario',
|
||||
'image' => 'food-festival.png',
|
||||
'image' => 'food-festival.avif',
|
||||
'weeks_from_now' => [3, 3],
|
||||
'day_offsets' => [0, 1],
|
||||
'time_start' => '12:00:00',
|
||||
|
|
@ -47,7 +49,7 @@ class TestEventsSeeder extends Seeder
|
|||
'subtitle' => 'Humor para compartir',
|
||||
'description' => 'Evento de prueba para visualizar distintas propuestas.',
|
||||
'location' => 'Centro Cultural La Comedia, Rosario',
|
||||
'image' => 'stand-up.png',
|
||||
'image' => 'stand-up.avif',
|
||||
'weeks_from_now' => [4],
|
||||
'time_start' => '20:30:00',
|
||||
'time_end' => '22:00:00',
|
||||
|
|
@ -74,14 +76,14 @@ class TestEventsSeeder extends Seeder
|
|||
}
|
||||
|
||||
if ($event->attachment_id === null) {
|
||||
$path = public_path('images/tennants/onticket/test-events/'.$definition['image']);
|
||||
$path = public_path(self::IMAGE_DIRECTORY.'/'.$definition['image']);
|
||||
|
||||
if (! is_file($path)) {
|
||||
throw new RuntimeException("Image not found at path: {$path}");
|
||||
}
|
||||
|
||||
$attachment = $this->attachmentService->store(
|
||||
new UploadedFile($path, $definition['image'], 'image/png', null, true),
|
||||
new UploadedFile($path, $definition['image'], 'image/avif', null, true),
|
||||
'tenants/onticket/events',
|
||||
);
|
||||
$event->update(['attachment_id' => $attachment->id]);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="63" height="36" viewBox="0 0 63 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M44.64 0H17.94C8.05 0 0 8.05 0 17.94C0 27.83 8.05 35.88 17.94 35.88H44.64C54.53 35.88 62.58 27.83 62.58 17.94C62.58 8.05 54.53 0 44.64 0ZM44.62 31.78C36.98 31.78 30.79 25.59 30.79 17.95C30.79 10.31 36.98 4.12 44.62 4.12C52.26 4.12 58.45 10.31 58.45 17.95C58.45 25.59 52.26 31.78 44.62 31.78Z" fill="#FF7006"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 422 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -44,7 +44,7 @@ class TenantSeederTest extends TestCase
|
|||
$this->assertSame('onticket_logo.png', $tenant->headerLogo->filename);
|
||||
$this->assertSame('onticket_footer_logo.png', $tenant->footerLogo->filename);
|
||||
$this->assertSame('onticket_favicon.svg', $tenant->favicon->filename);
|
||||
$this->assertSame('onticket_header_background.png', $tenant->headerBackgroundImage->filename);
|
||||
$this->assertSame('onticket_header_background.avif', $tenant->headerBackgroundImage->filename);
|
||||
|
||||
foreach ([$tenant->headerLogo, $tenant->footerLogo, $tenant->favicon, $tenant->headerBackgroundImage] as $attachment) {
|
||||
Storage::disk('s3')->assertExists($attachment->path);
|
||||
|
|
@ -56,12 +56,12 @@ class TenantSeederTest extends TestCase
|
|||
$imageIds = $carousel->config;
|
||||
$this->assertCount(8, $imageIds);
|
||||
$this->assertSame([
|
||||
'onticket_hero_carousel_1.png',
|
||||
'onticket_hero_carousel_2.png',
|
||||
'onticket_hero_carousel_1.avif',
|
||||
'onticket_hero_carousel_2.avif',
|
||||
'onticket_hero_carousel_3.avif',
|
||||
'onticket_hero_carousel_4.jfif',
|
||||
'onticket_hero_carousel_5.jfif',
|
||||
'onticket_hero_carousel_6.jfif',
|
||||
'onticket_hero_carousel_4.avif',
|
||||
'onticket_hero_carousel_5.avif',
|
||||
'onticket_hero_carousel_6.avif',
|
||||
'onticket_hero_carousel_7.avif',
|
||||
'onticket_hero_carousel_8.avif',
|
||||
], array_map(fn (int $id): string => Attachment::query()->findOrFail($id)->filename, $imageIds));
|
||||
|
|
|
|||
|
|
@ -29,11 +29,16 @@ class TestEventsSeederTest extends TestCase
|
|||
$events = $tenant->events()->with('dates.validityTime')->get();
|
||||
$this->assertCount(3, $events);
|
||||
$this->assertSame(4, $events->sum(fn ($event): int => $event->dates->count()));
|
||||
$this->assertEqualsCanonicalizing(
|
||||
['live-music.avif', 'food-festival.avif', 'stand-up.avif'],
|
||||
$events->map(fn ($event): string => $event->attachment->filename)->all(),
|
||||
);
|
||||
|
||||
foreach ($events as $event) {
|
||||
$this->assertTrue($event->published_at->isPast());
|
||||
$this->assertNotNull($event->date_text);
|
||||
$this->assertNotNull($event->attachment_id);
|
||||
$this->assertSame('image/avif', $event->attachment->mime_type);
|
||||
Storage::disk('s3')->assertExists($event->attachment->path);
|
||||
|
||||
foreach ($event->dates as $date) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue