Commit fa4c5088 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix(website): validate section + theme edits and keep unpublished sites private

Section and theme editors wrote straight to columns that carry CHECK
constraints, so a bad value surfaced as a 500 rather than a field error.
Adds rules() mirroring the constraints, Arabic messages(), and an error
summary in both forms.

home() also served unpublished sites to the public. Staff keep their
preview route; everyone else is sent to login.

Drops a redundant invalidateAll() from ThemeEditor::save(): the call
passed an argument the method does not take, and would have flushed
every tenant's cache. WebsiteSettingService::update() already
invalidates the one academy that changed.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
parent cd2faefd
......@@ -27,6 +27,7 @@ class Media extends Model
'file_size',
'alt_text',
'alt_text_ar',
'gallery_category',
'mediable_type',
'mediable_id',
'sort_order',
......
......@@ -30,6 +30,12 @@ public function home()
}
$settings = $this->settingService->getOrCreate($academy);
// Unpublished sites are not public — staff can still reach them via /manage/website/preview.
if (!$settings->is_published) {
return redirect()->route('login');
}
app()->instance('current_academy', $academy);
app()->instance('website_settings', $settings);
......
......@@ -145,8 +145,58 @@ public function editSection(string $key): void
}
}
/**
* Mirrors the CHECK constraints on website_sections (phase A migration)
* and the column types from the original create migration.
*/
public function rules(): array
{
return [
'sectionTitle' => 'nullable|string|max:255',
'sectionTitleEn' => 'nullable|string|max:255',
'sectionSubtitle' => 'nullable|string|max:255',
'sectionSubtitleEn' => 'nullable|string|max:255',
'sectionContent' => 'nullable|string',
'sectionContentEn' => 'nullable|string',
'heroVariant' => 'required|in:fullscreen,split_right,split_left,centered_minimal,video_bg,slideshow',
'sectionLayout' => 'required|string|max:30',
'sectionBgType' => 'required|in:inherit,solid,gradient,image,video',
'sectionBgColor' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sectionBgGradientFrom' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sectionBgGradientTo' => 'required|regex:/^#[0-9a-fA-F]{6}$/',
'sectionBgGradientAngle' => 'required|integer|min:0|max:360',
'sectionBgOverlayOpacity' => 'required|integer|min:0|max:100',
'sectionAnimation' => 'required|in:none,fade-up,fade-down,fade-left,fade-right,zoom-in,flip,bounce',
'sectionPaddingY' => 'required|in:inherit,none,small,medium,large,xlarge',
'sectionHiddenOnMobile' => 'boolean',
];
}
public function messages(): array
{
return [
'sectionTitle.max' => 'العنوان طويل جدًا (الحد الأقصى 255 حرفًا)',
'sectionTitleEn.max' => 'العنوان بالإنجليزية طويل جدًا (الحد الأقصى 255 حرفًا)',
'sectionSubtitle.max' => 'العنوان الفرعي طويل جدًا (الحد الأقصى 255 حرفًا)',
'sectionSubtitleEn.max' => 'العنوان الفرعي بالإنجليزية طويل جدًا (الحد الأقصى 255 حرفًا)',
'heroVariant.in' => 'شكل البانر المختار غير صالح',
'sectionBgType.in' => 'نوع الخلفية المختار غير صالح',
'sectionBgColor.regex' => 'لون الخلفية غير صالح',
'sectionBgGradientFrom.regex' => 'لون بداية التدرج غير صالح',
'sectionBgGradientTo.regex' => 'لون نهاية التدرج غير صالح',
'sectionBgGradientAngle.min' => 'زاوية التدرج يجب أن تكون بين 0 و 360',
'sectionBgGradientAngle.max' => 'زاوية التدرج يجب أن تكون بين 0 و 360',
'sectionBgOverlayOpacity.min' => 'شفافية الطبقة يجب أن تكون بين 0 و 100',
'sectionBgOverlayOpacity.max' => 'شفافية الطبقة يجب أن تكون بين 0 و 100',
'sectionAnimation.in' => 'تأثير الدخول المختار غير صالح',
'sectionPaddingY.in' => 'المسافة الداخلية المختارة غير صالحة',
];
}
public function saveSection(): void
{
$this->validate();
$academy = app('current_academy');
$section = WebsiteSection::withoutGlobalScope('academy')
->where('academy_id', $academy->id)
......
......@@ -2,7 +2,6 @@
namespace App\Livewire\Website;
use App\Domain\Website\Services\WebsiteCacheService;
use App\Domain\Website\Services\WebsiteSettingService;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
......@@ -277,8 +276,6 @@ public function save(): void
'facebook_pixel_id' => $this->facebook_pixel_id,
]);
app(WebsiteCacheService::class)->invalidateAll(app('current_academy'));
session()->flash('success', __('تم حفظ إعدادات التصميم بنجاح'));
}
......
......@@ -128,6 +128,17 @@ class="relative shrink-0 w-9 h-5 rounded-full transition-colors {{ $section['is_
</div>
<form wire:submit="saveSection" class="space-y-5">
@if($errors->any())
<div class="p-3 rounded-lg bg-red-50 border border-red-200 text-red-700 text-sm">
<p class="font-medium mb-1">تعذّر الحفظ — راجع الحقول التالية:</p>
<ul class="list-disc list-inside space-y-0.5">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
{{-- Title --}}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
......
......@@ -23,6 +23,17 @@ class="mb-4 p-3 rounded-lg bg-green-50 border border-green-200 text-green-700 te
</div>
@endif
@if($errors->any())
<div class="p-3 rounded-lg bg-red-50 border border-red-200 text-red-700 text-sm">
<p class="font-medium mb-1">تعذّر الحفظ — راجع الحقول التالية:</p>
<ul class="list-disc list-inside space-y-0.5">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form wire:submit="save" class="space-y-6">
{{-- Template Presets --}}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment