174 lines
7.8 KiB
PHP
174 lines
7.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Requests\Collections;
|
|
|
|
use App\Models\Collection;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
use Illuminate\Support\Str;
|
|
|
|
class StoreCollectionRequest extends FormRequest
|
|
{
|
|
public function authorize(): bool
|
|
{
|
|
return $this->user() !== null;
|
|
}
|
|
|
|
protected function prepareForValidation(): void
|
|
{
|
|
$title = (string) $this->input('title', '');
|
|
$slug = (string) $this->input('slug', '');
|
|
$mode = (string) ($this->input('mode') ?: Collection::MODE_MANUAL);
|
|
$sortMode = (string) ($this->input('sort_mode') ?: ($mode === Collection::MODE_SMART ? Collection::SORT_NEWEST : Collection::SORT_MANUAL));
|
|
|
|
if ($slug === '' && $title !== '') {
|
|
$slug = Str::slug(Str::limit($title, 140, ''));
|
|
}
|
|
|
|
$this->merge([
|
|
'slug' => $slug,
|
|
'mode' => $mode,
|
|
'sort_mode' => $sortMode,
|
|
]);
|
|
}
|
|
|
|
public function rules(): array
|
|
{
|
|
return [
|
|
'title' => ['required', 'string', 'min:2', 'max:120'],
|
|
'slug' => ['required', 'string', 'min:2', 'max:140', 'regex:/^[a-z0-9]+(?:-[a-z0-9]+)*$/'],
|
|
'type' => ['nullable', 'in:' . implode(',', [
|
|
Collection::TYPE_PERSONAL,
|
|
Collection::TYPE_COMMUNITY,
|
|
Collection::TYPE_EDITORIAL,
|
|
])],
|
|
'editorial_owner_mode' => ['nullable', 'in:' . implode(',', [
|
|
Collection::EDITORIAL_OWNER_CREATOR,
|
|
Collection::EDITORIAL_OWNER_STAFF_ACCOUNT,
|
|
Collection::EDITORIAL_OWNER_SYSTEM,
|
|
])],
|
|
'editorial_owner_username' => ['nullable', 'string', 'max:60'],
|
|
'editorial_owner_label' => ['nullable', 'string', 'max:120'],
|
|
'description' => ['nullable', 'string', 'max:1000'],
|
|
'subtitle' => ['nullable', 'string', 'max:160'],
|
|
'summary' => ['nullable', 'string', 'max:320'],
|
|
'lifecycle_state' => ['nullable', 'in:' . implode(',', [
|
|
Collection::LIFECYCLE_DRAFT,
|
|
Collection::LIFECYCLE_SCHEDULED,
|
|
Collection::LIFECYCLE_PUBLISHED,
|
|
Collection::LIFECYCLE_FEATURED,
|
|
Collection::LIFECYCLE_ARCHIVED,
|
|
Collection::LIFECYCLE_EXPIRED,
|
|
])],
|
|
'collaboration_mode' => ['nullable', 'in:' . implode(',', [
|
|
Collection::COLLABORATION_CLOSED,
|
|
Collection::COLLABORATION_INVITE_ONLY,
|
|
Collection::COLLABORATION_OPEN,
|
|
])],
|
|
'allow_submissions' => ['nullable', 'boolean'],
|
|
'allow_comments' => ['nullable', 'boolean'],
|
|
'allow_saves' => ['nullable', 'boolean'],
|
|
'event_key' => ['nullable', 'string', 'max:80'],
|
|
'event_label' => ['nullable', 'string', 'max:120'],
|
|
'season_key' => ['nullable', 'string', 'max:80'],
|
|
'banner_text' => ['nullable', 'string', 'max:200'],
|
|
'badge_label' => ['nullable', 'string', 'max:80'],
|
|
'spotlight_style' => ['nullable', 'in:' . implode(',', [
|
|
Collection::SPOTLIGHT_STYLE_DEFAULT,
|
|
Collection::SPOTLIGHT_STYLE_EDITORIAL,
|
|
Collection::SPOTLIGHT_STYLE_SEASONAL,
|
|
Collection::SPOTLIGHT_STYLE_CHALLENGE,
|
|
Collection::SPOTLIGHT_STYLE_COMMUNITY,
|
|
])],
|
|
'analytics_enabled' => ['nullable', 'boolean'],
|
|
'presentation_style' => ['nullable', 'in:' . implode(',', [
|
|
Collection::PRESENTATION_STANDARD,
|
|
Collection::PRESENTATION_EDITORIAL_GRID,
|
|
Collection::PRESENTATION_HERO_GRID,
|
|
Collection::PRESENTATION_MASONRY,
|
|
])],
|
|
'emphasis_mode' => ['nullable', 'in:' . implode(',', [
|
|
Collection::EMPHASIS_COVER_HEAVY,
|
|
Collection::EMPHASIS_BALANCED,
|
|
Collection::EMPHASIS_ARTWORK_FIRST,
|
|
])],
|
|
'theme_token' => ['nullable', 'in:default,subtle-blue,violet,amber'],
|
|
'series_key' => ['nullable', 'string', 'max:80'],
|
|
'series_title' => ['nullable', 'string', 'max:160'],
|
|
'series_description' => ['nullable', 'string', 'max:400'],
|
|
'series_order' => ['nullable', 'integer', 'min:1', 'max:9999'],
|
|
'campaign_key' => ['nullable', 'string', 'max:80'],
|
|
'campaign_label' => ['nullable', 'string', 'max:120'],
|
|
'commercial_eligibility' => ['nullable', 'boolean'],
|
|
'promotion_tier' => ['nullable', 'string', 'max:40'],
|
|
'sponsorship_label' => ['nullable', 'string', 'max:120'],
|
|
'partner_label' => ['nullable', 'string', 'max:120'],
|
|
'monetization_ready_status' => ['nullable', 'string', 'max:40'],
|
|
'brand_safe_status' => ['nullable', 'string', 'max:40'],
|
|
'published_at' => ['nullable', 'date'],
|
|
'unpublished_at' => ['nullable', 'date', 'after:published_at'],
|
|
'archived_at' => ['nullable', 'date'],
|
|
'expired_at' => ['nullable', 'date'],
|
|
'visibility' => ['required', 'in:' . implode(',', [
|
|
Collection::VISIBILITY_PUBLIC,
|
|
Collection::VISIBILITY_UNLISTED,
|
|
Collection::VISIBILITY_PRIVATE,
|
|
])],
|
|
'mode' => ['required', 'in:' . implode(',', [
|
|
Collection::MODE_MANUAL,
|
|
Collection::MODE_SMART,
|
|
])],
|
|
'sort_mode' => ['nullable', 'in:' . implode(',', [
|
|
Collection::SORT_MANUAL,
|
|
Collection::SORT_NEWEST,
|
|
Collection::SORT_OLDEST,
|
|
Collection::SORT_POPULAR,
|
|
])],
|
|
'smart_rules_json' => ['nullable', 'array'],
|
|
'layout_modules_json' => ['nullable', 'array'],
|
|
'layout_modules_json.*.key' => ['required_with:layout_modules_json', 'string', 'max:60'],
|
|
'layout_modules_json.*.enabled' => ['nullable', 'boolean'],
|
|
'layout_modules_json.*.slot' => ['nullable', 'string', 'max:20'],
|
|
];
|
|
}
|
|
|
|
public function withValidator($validator): void
|
|
{
|
|
$validator->after(function ($validator): void {
|
|
$type = (string) ($this->input('type') ?: Collection::TYPE_PERSONAL);
|
|
|
|
if ($type === Collection::TYPE_EDITORIAL && ! $this->user()?->hasRole('admin')) {
|
|
$validator->errors()->add('type', 'Only staff can create editorial collections.');
|
|
}
|
|
|
|
if ($type === Collection::TYPE_EDITORIAL && (string) $this->input('editorial_owner_mode') === Collection::EDITORIAL_OWNER_STAFF_ACCOUNT) {
|
|
$username = trim((string) $this->input('editorial_owner_username', ''));
|
|
|
|
if ($username === '') {
|
|
$validator->errors()->add('editorial_owner_username', 'Choose the staff account that should own this editorial collection.');
|
|
} else {
|
|
$target = User::query()->whereRaw('LOWER(username) = ?', [Str::lower($username)])->first();
|
|
|
|
if (! $target || ! ($target->isAdmin() || $target->isModerator())) {
|
|
$validator->errors()->add('editorial_owner_username', 'The editorial owner must be an admin or moderator account.');
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($this->filled('unpublished_at') && ! $this->filled('published_at')) {
|
|
$validator->errors()->add('published_at', 'Set a publish time before adding an unpublish time.');
|
|
}
|
|
|
|
if ((string) $this->input('mode') !== Collection::MODE_SMART) {
|
|
return;
|
|
}
|
|
|
|
if (! is_array($this->input('smart_rules_json'))) {
|
|
$validator->errors()->add('smart_rules_json', 'Smart collections require at least one valid rule.');
|
|
}
|
|
});
|
|
}
|
|
}
|