feat(tenant): add site title and favicon support for tenants and website types
This commit is contained in:
@@ -21,6 +21,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
'codigo',
|
||||
'nombre',
|
||||
'dominio',
|
||||
'site_title',
|
||||
'primary_color',
|
||||
'secondary_color',
|
||||
'danger_color',
|
||||
@@ -29,6 +30,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
'footer_bg_color',
|
||||
'header_logo_id',
|
||||
'footer_logo_id',
|
||||
'favicon_id',
|
||||
'header_bg_image_id',
|
||||
'footer_bg_image_id',
|
||||
'website_type_code',
|
||||
@@ -101,6 +103,14 @@ class Tenant extends Model
|
||||
return $this->belongsTo(Attachment::class, 'footer_logo_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Attachment, $this>
|
||||
*/
|
||||
public function favicon(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Attachment::class, 'favicon_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Attachment, $this>
|
||||
*/
|
||||
|
||||
@@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
'nombre',
|
||||
'dominio',
|
||||
'scanner_domain',
|
||||
'site_title',
|
||||
'primary_color',
|
||||
'secondary_color',
|
||||
'danger_color',
|
||||
@@ -27,6 +28,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
'login_header_footer_color',
|
||||
'site_logo',
|
||||
'footer_logo',
|
||||
'favicon_id',
|
||||
])]
|
||||
class WebsiteType extends Model
|
||||
{
|
||||
@@ -50,6 +52,14 @@ class WebsiteType extends Model
|
||||
return $this->belongsTo(Attachment::class, 'footer_logo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo<Attachment, $this>
|
||||
*/
|
||||
public function favicon(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Attachment::class, 'favicon_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HasMany<WebsiteTypeExtra, $this>
|
||||
*/
|
||||
|
||||
@@ -55,6 +55,7 @@ class StoreTenantRequest extends FormRequest
|
||||
'max:255',
|
||||
Rule::unique('tenants', 'dominio'),
|
||||
],
|
||||
'site_title' => ['sometimes', 'nullable', 'string', 'max:255'],
|
||||
'primary_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'secondary_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'danger_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
@@ -63,6 +64,7 @@ class StoreTenantRequest extends FormRequest
|
||||
'footer_bg_color' => ['required', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'header_logo' => $logoRule,
|
||||
'footer_logo' => $logoRule,
|
||||
'favicon' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'header_bg_image' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'footer_bg_image' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'social_media' => ['sometimes', 'array'],
|
||||
|
||||
@@ -65,6 +65,7 @@ class UpdateTenantRequest extends FormRequest
|
||||
'max:255',
|
||||
Rule::unique('tenants', 'dominio')->ignore($tenant?->id),
|
||||
],
|
||||
'site_title' => ['sometimes', 'nullable', 'string', 'max:255'],
|
||||
'primary_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'secondary_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'danger_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
@@ -73,6 +74,7 @@ class UpdateTenantRequest extends FormRequest
|
||||
'footer_bg_color' => ['nullable', 'string', 'regex:/^#([a-fA-F0-9]{3,4}|[a-fA-F0-9]{6}|[a-fA-F0-9]{8})$/'],
|
||||
'header_logo' => $logoRule,
|
||||
'footer_logo' => $logoRule,
|
||||
'favicon' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'header_bg_image' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'footer_bg_image' => ['sometimes', 'nullable', new ImageOrBase64Rule],
|
||||
'social_media' => ['sometimes', 'array'],
|
||||
|
||||
@@ -26,6 +26,11 @@ class TenantResource extends JsonResource
|
||||
'codigo' => $this->codigo,
|
||||
'nombre' => $this->nombre,
|
||||
'dominio' => $this->dominio,
|
||||
'site_title' => $this->site_title
|
||||
?? $this->websiteType?->site_title
|
||||
?? 'ShopitFront',
|
||||
'favicon' => ($this->favicon ?? $this->websiteType?->favicon)
|
||||
?->getTemporaryUrl(1440),
|
||||
'primary_color' => $this->primary_color,
|
||||
'secondary_color' => $this->secondary_color,
|
||||
'danger_color' => $this->danger_color,
|
||||
|
||||
@@ -13,6 +13,8 @@ class TenantInformationService
|
||||
private const DEFAULT_RELATIONS = [
|
||||
'headerLogo',
|
||||
'footerLogo',
|
||||
'favicon',
|
||||
'websiteType.favicon',
|
||||
'headerBackgroundImage',
|
||||
'footerBackgroundImage',
|
||||
'socialMedia',
|
||||
|
||||
@@ -25,6 +25,7 @@ class TenantService
|
||||
return DB::transaction(function () use ($data): Tenant {
|
||||
$headerLogo = $data['header_logo'] ?? null;
|
||||
$footerLogo = $data['footer_logo'] ?? null;
|
||||
$favicon = $data['favicon'] ?? null;
|
||||
$headerBackgroundImage = $data['header_bg_image'] ?? null;
|
||||
$footerBackgroundImage = $data['footer_bg_image'] ?? null;
|
||||
$socialMedia = $data['social_media'] ?? [];
|
||||
@@ -33,6 +34,7 @@ class TenantService
|
||||
unset(
|
||||
$data['header_logo'],
|
||||
$data['footer_logo'],
|
||||
$data['favicon'],
|
||||
$data['header_bg_image'],
|
||||
$data['footer_bg_image'],
|
||||
$data['social_media'],
|
||||
@@ -63,6 +65,7 @@ class TenantService
|
||||
|
||||
$data['header_logo_id'] = $headerAttachmentId;
|
||||
$data['footer_logo_id'] = $footerAttachmentId;
|
||||
$data['favicon_id'] = $this->storeTenantImage($favicon);
|
||||
$data['header_bg_image_id'] = $this->storeTenantImage($headerBackgroundImage);
|
||||
$data['footer_bg_image_id'] = $this->storeTenantImage($footerBackgroundImage);
|
||||
|
||||
@@ -85,11 +88,13 @@ class TenantService
|
||||
return DB::transaction(function () use ($tenant, $data): Tenant {
|
||||
$hasHeaderLogoKey = array_key_exists('header_logo', $data);
|
||||
$hasFooterLogoKey = array_key_exists('footer_logo', $data);
|
||||
$hasFaviconKey = array_key_exists('favicon', $data);
|
||||
$hasHeaderBackgroundImageKey = array_key_exists('header_bg_image', $data);
|
||||
$hasFooterBackgroundImageKey = array_key_exists('footer_bg_image', $data);
|
||||
$hasSocialMediaKey = array_key_exists('social_media', $data);
|
||||
$headerLogo = $data['header_logo'] ?? null;
|
||||
$footerLogo = $data['footer_logo'] ?? null;
|
||||
$favicon = $data['favicon'] ?? null;
|
||||
$headerBackgroundImage = $data['header_bg_image'] ?? null;
|
||||
$footerBackgroundImage = $data['footer_bg_image'] ?? null;
|
||||
$socialMedia = $data['social_media'] ?? [];
|
||||
@@ -97,6 +102,7 @@ class TenantService
|
||||
unset(
|
||||
$data['header_logo'],
|
||||
$data['footer_logo'],
|
||||
$data['favicon'],
|
||||
$data['header_bg_image'],
|
||||
$data['footer_bg_image'],
|
||||
$data['social_media']
|
||||
@@ -136,6 +142,10 @@ class TenantService
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasFaviconKey) {
|
||||
$tenant->favicon_id = $this->storeTenantImage($favicon);
|
||||
}
|
||||
|
||||
if ($hasHeaderBackgroundImageKey) {
|
||||
$tenant->header_bg_image_id = $this->storeTenantImage($headerBackgroundImage);
|
||||
}
|
||||
|
||||
@@ -46,14 +46,20 @@ class WebsiteTypeService
|
||||
return DB::transaction(function () use ($websiteType, $data): WebsiteType {
|
||||
$previousLogos = [];
|
||||
|
||||
foreach (['site_logo' => 'siteLogo', 'footer_logo' => 'footerLogo'] as $field => $relation) {
|
||||
$attachmentFields = [
|
||||
'site_logo' => ['relation' => 'siteLogo', 'column' => 'site_logo'],
|
||||
'footer_logo' => ['relation' => 'footerLogo', 'column' => 'footer_logo'],
|
||||
'favicon' => ['relation' => 'favicon', 'column' => 'favicon_id'],
|
||||
];
|
||||
|
||||
foreach ($attachmentFields as $field => $attachmentField) {
|
||||
if (! array_key_exists($field, $data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$logo = $data[$field];
|
||||
$previousLogos[$field] = $websiteType->exists
|
||||
? $websiteType->{$relation}()->first()
|
||||
? $websiteType->{$attachmentField['relation']}()->first()
|
||||
: null;
|
||||
unset($data[$field]);
|
||||
|
||||
@@ -65,17 +71,17 @@ class WebsiteTypeService
|
||||
: $this->attachmentService->store($logo, 'website-types');
|
||||
}
|
||||
|
||||
$data[$field] = $attachment?->id;
|
||||
$data[$attachmentField['column']] = $attachment?->id;
|
||||
}
|
||||
|
||||
$websiteType->fill($data)->save();
|
||||
|
||||
foreach ($previousLogos as $field => $previousLogo) {
|
||||
foreach ($previousLogos as $previousLogo) {
|
||||
if (
|
||||
$previousLogo instanceof Attachment
|
||||
&& $previousLogo->id !== $websiteType->{$field}
|
||||
&& $previousLogo->id !== $websiteType->site_logo
|
||||
&& $previousLogo->id !== $websiteType->footer_logo
|
||||
&& $previousLogo->id !== $websiteType->favicon_id
|
||||
) {
|
||||
$this->attachmentService->delete($previousLogo);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('website_type', function (Blueprint $table): void {
|
||||
$table->string('site_title')->nullable()->after('scanner_domain');
|
||||
$table->unsignedBigInteger('favicon_id')->nullable()->after('footer_logo');
|
||||
|
||||
$table->foreign('favicon_id')
|
||||
->references('id')
|
||||
->on('attachments')
|
||||
->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::table('tenants', function (Blueprint $table): void {
|
||||
$table->string('site_title')->nullable()->after('dominio');
|
||||
$table->unsignedBigInteger('favicon_id')->nullable()->after('footer_logo_id');
|
||||
|
||||
$table->foreign('favicon_id')
|
||||
->references('id')
|
||||
->on('attachments')
|
||||
->nullOnDelete();
|
||||
});
|
||||
|
||||
DB::table('website_type')
|
||||
->whereNull('site_title')
|
||||
->update(['site_title' => DB::raw('nombre')]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('tenants', function (Blueprint $table): void {
|
||||
if (Schema::getConnection()->getDriverName() !== 'sqlite') {
|
||||
$table->dropForeign(['favicon_id']);
|
||||
}
|
||||
|
||||
$table->dropColumn(['site_title', 'favicon_id']);
|
||||
});
|
||||
|
||||
Schema::table('website_type', function (Blueprint $table): void {
|
||||
if (Schema::getConnection()->getDriverName() !== 'sqlite') {
|
||||
$table->dropForeign(['favicon_id']);
|
||||
}
|
||||
|
||||
$table->dropColumn(['site_title', 'favicon_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/** @var array<string, array{title: string, image: string, filename: string}> */
|
||||
private const BRANDING = [
|
||||
'fiesta_futbol_infantil' => [
|
||||
'title' => 'Fiesta Fútbol Infantil',
|
||||
'image' => 'images/tennants/fiesta_futbol_infantil/futbol_infantil_favicon.png',
|
||||
'filename' => 'futbol_infantil_favicon.png',
|
||||
],
|
||||
'desfile_pura_tendencia' => [
|
||||
'title' => 'Desfile Pura Tendencia',
|
||||
'image' => 'images/tennants/desfile_pura_tendencia/pura_tendencia_favicon.png',
|
||||
'filename' => 'pura_tendencia_favicon.png',
|
||||
],
|
||||
];
|
||||
|
||||
/** @var list<string> */
|
||||
private array $storedPaths = [];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
try {
|
||||
DB::transaction(function (): void {
|
||||
foreach (self::BRANDING as $tenantCode => $branding) {
|
||||
$tenant = DB::table('tenants')
|
||||
->where('codigo', $tenantCode)
|
||||
->first(['id', 'favicon_id']);
|
||||
|
||||
if ($tenant === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$faviconId = $tenant->favicon_id;
|
||||
$currentFilename = $faviconId === null
|
||||
? null
|
||||
: DB::table('attachments')->where('id', $faviconId)->value('filename');
|
||||
|
||||
if ($currentFilename !== $branding['filename']) {
|
||||
$faviconId = $this->storeFavicon(
|
||||
$tenantCode,
|
||||
$branding['image'],
|
||||
$branding['filename'],
|
||||
);
|
||||
}
|
||||
|
||||
DB::table('tenants')
|
||||
->where('id', $tenant->id)
|
||||
->update([
|
||||
'site_title' => $branding['title'],
|
||||
'favicon_id' => $faviconId,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
});
|
||||
} catch (Throwable $throwable) {
|
||||
Storage::disk('s3')->delete($this->storedPaths);
|
||||
|
||||
throw $throwable;
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (self::BRANDING as $tenantCode => $branding) {
|
||||
$tenant = DB::table('tenants')
|
||||
->where('codigo', $tenantCode)
|
||||
->first(['id', 'site_title', 'favicon_id']);
|
||||
|
||||
if ($tenant === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$favicon = $tenant->favicon_id === null
|
||||
? null
|
||||
: DB::table('attachments')->where('id', $tenant->favicon_id)->first();
|
||||
|
||||
DB::table('tenants')
|
||||
->where('id', $tenant->id)
|
||||
->update([
|
||||
'site_title' => $tenant->site_title === $branding['title'] ? null : $tenant->site_title,
|
||||
'favicon_id' => $favicon?->filename === $branding['filename'] ? null : $tenant->favicon_id,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
if ($favicon?->filename === $branding['filename']) {
|
||||
Storage::disk('s3')->delete($favicon->path);
|
||||
DB::table('attachments')->where('id', $favicon->id)->delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function storeFavicon(string $tenantCode, string $relativePath, string $filename): int
|
||||
{
|
||||
$sourcePath = public_path($relativePath);
|
||||
|
||||
if (! is_file($sourcePath)) {
|
||||
throw new RuntimeException("Favicon not found at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$contents = file_get_contents($sourcePath);
|
||||
|
||||
if ($contents === false) {
|
||||
throw new RuntimeException("Could not read favicon at path: {$sourcePath}");
|
||||
}
|
||||
|
||||
$key = (string) Str::uuid();
|
||||
$storedPath = "tenants/{$tenantCode}/{$key}.png";
|
||||
|
||||
if (! Storage::disk('s3')->put($storedPath, $contents)) {
|
||||
throw new RuntimeException("Could not store favicon at path: {$storedPath}");
|
||||
}
|
||||
|
||||
$this->storedPaths[] = $storedPath;
|
||||
|
||||
return DB::table('attachments')->insertGetId([
|
||||
'key' => $key,
|
||||
'path' => $storedPath,
|
||||
'filename' => $filename,
|
||||
'type' => 'image',
|
||||
'mime_type' => 'image/png',
|
||||
'extension' => 'png',
|
||||
'size' => strlen($contents),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
};
|
||||
@@ -104,6 +104,7 @@ class TenantSeeder extends Seeder
|
||||
'codigo' => 'fiesta_futbol_infantil',
|
||||
'nombre' => 'Fiesta Fútbol Infantil',
|
||||
'dominio' => $fiestaDomain,
|
||||
'site_title' => 'Fiesta Fútbol Infantil',
|
||||
'primary_color' => '#00973F',
|
||||
'secondary_color' => '#A0A0A0',
|
||||
'danger_color' => '#FF8888',
|
||||
@@ -121,6 +122,10 @@ class TenantSeeder extends Seeder
|
||||
'images/tennants/fiesta_futbol_infantil/futbol_infantil_footer.png',
|
||||
'futbol_infantil_footer.png',
|
||||
),
|
||||
'favicon' => $this->uploadedImage(
|
||||
'images/tennants/fiesta_futbol_infantil/futbol_infantil_favicon.png',
|
||||
'futbol_infantil_favicon.png',
|
||||
),
|
||||
'social_media' => self::SOCIAL_MEDIA,
|
||||
'website_type_code' => 'onticket',
|
||||
'extras' => [
|
||||
@@ -229,6 +234,18 @@ class TenantSeeder extends Seeder
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$tenant->favicon
|
||||
&& $tenant->favicon_id !== $tenant->header_logo_id
|
||||
&& $tenant->favicon_id !== $tenant->footer_logo_id
|
||||
) {
|
||||
try {
|
||||
$attachmentService->delete($tenant->favicon);
|
||||
} catch (Throwable) {
|
||||
// Ignore cleanup errors while recreating demo data.
|
||||
}
|
||||
}
|
||||
|
||||
$tenant->delete();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ class WebsiteTypeSeeder extends Seeder
|
||||
'nombre' => 'ShopIt',
|
||||
'dominio' => 'localhost',
|
||||
'scanner_domain' => 'scanner.localhost',
|
||||
'site_title' => 'ShopIt',
|
||||
...self::PRESENTATION,
|
||||
'site_logo' => $this->onTicketLogo(),
|
||||
'footer_logo' => $this->onTicketFooterLogo(),
|
||||
@@ -65,6 +66,7 @@ class WebsiteTypeSeeder extends Seeder
|
||||
'nombre' => 'OnTicket',
|
||||
'dominio' => 'onticket.localhost',
|
||||
'scanner_domain' => 'scanner.onticket.localhost',
|
||||
'site_title' => 'OnTicket',
|
||||
...self::PRESENTATION,
|
||||
'site_logo' => $this->onTicketLogo(),
|
||||
'footer_logo' => $this->onTicketFooterLogo(),
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 803 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -36,6 +36,11 @@ class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
||||
);
|
||||
$footerBackgroundMigration->up();
|
||||
|
||||
$browserBrandingMigration = require database_path(
|
||||
'migrations/2026_08_14_010000_set_seeded_tenant_browser_branding.php'
|
||||
);
|
||||
$browserBrandingMigration->up();
|
||||
|
||||
$this->assertDatabaseHas('tenants', [
|
||||
'codigo' => 'desfile_pura_tendencia',
|
||||
'nombre' => 'Desfile Pura Tendencia',
|
||||
@@ -52,8 +57,25 @@ class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
||||
'footer_bg_color' => '#D4441C',
|
||||
'display_categories' => false,
|
||||
'display_seach_bar' => false,
|
||||
'site_title' => 'Desfile Pura Tendencia',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('tenants', [
|
||||
'codigo' => 'fiesta_futbol_infantil',
|
||||
'site_title' => 'Fiesta Fútbol Infantil',
|
||||
]);
|
||||
|
||||
foreach ([
|
||||
'fiesta_futbol_infantil' => 'futbol_infantil_favicon.png',
|
||||
'desfile_pura_tendencia' => 'pura_tendencia_favicon.png',
|
||||
] as $tenantCode => $faviconFilename) {
|
||||
$faviconId = DB::table('tenants')->where('codigo', $tenantCode)->value('favicon_id');
|
||||
$favicon = DB::table('attachments')->where('id', $faviconId)->sole();
|
||||
|
||||
$this->assertSame($faviconFilename, $favicon->filename);
|
||||
Storage::disk('s3')->assertExists($favicon->path);
|
||||
}
|
||||
|
||||
$eventDate = DB::table('event_dates')
|
||||
->where('tenant_code', 'desfile_pura_tendencia')
|
||||
->sole();
|
||||
@@ -104,6 +126,7 @@ class CreateDesfilePuraTendenciaTenantTest extends TestCase
|
||||
'desfile_pura_tendencia_footer.png',
|
||||
'desfile_pura_tendencia_hero.png',
|
||||
'desfile_pura_tendencia_footer_background.png',
|
||||
'pura_tendencia_favicon.png',
|
||||
'entrada_pasarela.png',
|
||||
] as $filename) {
|
||||
$path = DB::table('attachments')->where('filename', $filename)->value('path');
|
||||
|
||||
@@ -127,6 +127,62 @@ class BootstrapTenantControllerTest extends TestCase
|
||||
->assertJsonPath('data.dominio', 'acme.com');
|
||||
}
|
||||
|
||||
public function test_it_resolves_browser_branding_from_the_tenant_before_the_website_type(): void
|
||||
{
|
||||
$typeFavicon = Attachment::query()->create([
|
||||
'key' => (string) Str::uuid(),
|
||||
'path' => 'website-types/type-favicon.png',
|
||||
'filename' => 'type-favicon.png',
|
||||
'type' => AttachmentType::Image,
|
||||
'mime_type' => 'image/png',
|
||||
]);
|
||||
$tenantFavicon = Attachment::query()->create([
|
||||
'key' => (string) Str::uuid(),
|
||||
'path' => 'tenants/tenant-favicon.png',
|
||||
'filename' => 'tenant-favicon.png',
|
||||
'type' => AttachmentType::Image,
|
||||
'mime_type' => 'image/png',
|
||||
]);
|
||||
$websiteType = WebsiteType::query()->create([
|
||||
'codigo' => 'store',
|
||||
'nombre' => 'Tienda',
|
||||
'site_title' => 'Website type title',
|
||||
'favicon_id' => $typeFavicon->id,
|
||||
]);
|
||||
$tenant = $this->createTenant([
|
||||
'website_type_code' => $websiteType->codigo,
|
||||
]);
|
||||
|
||||
$typeResponse = $this->getJson('/api/tenants/bootstrap/acme.com');
|
||||
|
||||
$typeResponse
|
||||
->assertOk()
|
||||
->assertJsonPath('data.site_title', 'Website type title');
|
||||
$this->assertStringContainsString($typeFavicon->key, $typeResponse->json('data.favicon'));
|
||||
|
||||
$tenant->update([
|
||||
'site_title' => 'Tenant title',
|
||||
'favicon_id' => $tenantFavicon->id,
|
||||
]);
|
||||
|
||||
$tenantResponse = $this->getJson('/api/tenants/bootstrap/acme.com');
|
||||
|
||||
$tenantResponse
|
||||
->assertOk()
|
||||
->assertJsonPath('data.site_title', 'Tenant title');
|
||||
$this->assertStringContainsString($tenantFavicon->key, $tenantResponse->json('data.favicon'));
|
||||
}
|
||||
|
||||
public function test_it_uses_default_browser_branding_when_none_is_configured(): void
|
||||
{
|
||||
$this->createTenant();
|
||||
|
||||
$this->getJson('/api/tenants/bootstrap/acme.com')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.site_title', 'ShopitFront')
|
||||
->assertJsonPath('data.favicon', null);
|
||||
}
|
||||
|
||||
public function test_it_returns_only_the_tenant_categories_in_the_bootstrap(): void
|
||||
{
|
||||
$tenant = $this->createTenant();
|
||||
@@ -755,21 +811,28 @@ class BootstrapTenantControllerTest extends TestCase
|
||||
'footer_bg_color' => '#444444',
|
||||
'header_logo' => $base64Image,
|
||||
'footer_logo' => $ftrUuid,
|
||||
'site_title' => 'Acme Store',
|
||||
'favicon' => $base64Image,
|
||||
]);
|
||||
|
||||
$response->assertCreated();
|
||||
|
||||
$tenant = Tenant::query()->with('headerLogo')->where('codigo', 'acme')->firstOrFail();
|
||||
$tenant = Tenant::query()->with(['headerLogo', 'favicon'])->where('codigo', 'acme')->firstOrFail();
|
||||
|
||||
$this->assertNotNull($tenant->header_logo_id);
|
||||
$this->assertNotNull($tenant->favicon_id);
|
||||
|
||||
$headerUrl = $response->json('data.header_logo');
|
||||
$faviconUrl = $response->json('data.favicon');
|
||||
|
||||
$response->assertJsonPath('data.site_title', 'Acme Store');
|
||||
$this->assertStringContainsString($tenant->headerLogo->key, $headerUrl);
|
||||
$this->assertStringContainsString($tenant->favicon->key, $faviconUrl);
|
||||
$this->assertTrue(
|
||||
str_contains($headerUrl, 'Expires=') || str_contains($headerUrl, 'expiration=') || str_contains($headerUrl, 'X-Amz-Expires=')
|
||||
);
|
||||
|
||||
$this->assertDatabaseHas('attachments', ['key' => $tenant->headerLogo->key]);
|
||||
$this->assertDatabaseHas('attachments', ['key' => $tenant->favicon->key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,20 +32,26 @@ class WebsiteTypeServiceTest extends TestCase
|
||||
'background_color' => '#f8f8f8',
|
||||
'border_color' => '#dddddd',
|
||||
'login_header_footer_color' => '#333333',
|
||||
'site_title' => 'Marketplace Central',
|
||||
'site_logo' => UploadedFile::fake()->image('site-logo.png'),
|
||||
'footer_logo' => UploadedFile::fake()->image('footer-logo.png'),
|
||||
'favicon' => UploadedFile::fake()->image('favicon.png', 32, 32),
|
||||
]);
|
||||
|
||||
$siteLogo = $websiteType->siteLogo()->firstOrFail();
|
||||
$footerLogo = $websiteType->footerLogo()->firstOrFail();
|
||||
$favicon = $websiteType->favicon()->firstOrFail();
|
||||
|
||||
$this->assertSame('marketplace', $websiteType->codigo);
|
||||
$this->assertSame($siteLogo->id, $websiteType->site_logo);
|
||||
$this->assertSame($footerLogo->id, $websiteType->footer_logo);
|
||||
$this->assertSame($favicon->id, $websiteType->favicon_id);
|
||||
$this->assertStringStartsWith('website-types/', $siteLogo->path);
|
||||
$this->assertStringStartsWith('website-types/', $footerLogo->path);
|
||||
$this->assertStringStartsWith('website-types/', $favicon->path);
|
||||
Storage::disk('s3')->assertExists($siteLogo->path);
|
||||
Storage::disk('s3')->assertExists($footerLogo->path);
|
||||
Storage::disk('s3')->assertExists($favicon->path);
|
||||
$this->assertDatabaseHas('website_type', [
|
||||
'codigo' => 'marketplace',
|
||||
'dominio' => 'marketplace.test',
|
||||
@@ -57,8 +63,10 @@ class WebsiteTypeServiceTest extends TestCase
|
||||
'background_color' => '#f8f8f8',
|
||||
'border_color' => '#dddddd',
|
||||
'login_header_footer_color' => '#333333',
|
||||
'site_title' => 'Marketplace Central',
|
||||
'site_logo' => $siteLogo->id,
|
||||
'footer_logo' => $footerLogo->id,
|
||||
'favicon_id' => $favicon->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user