117 lines
5.6 KiB
PHP
117 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Collection;
|
|
use App\Models\User;
|
|
use App\Services\CollectionHistoryService;
|
|
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class CollectionPartnerProgramService
|
|
{
|
|
public function sync(Collection $collection, array $attributes, ?User $actor = null): Collection
|
|
{
|
|
$adminOnlyKeys = [
|
|
'partner_key',
|
|
'trust_tier',
|
|
'sponsorship_state',
|
|
'ownership_domain',
|
|
'commercial_review_state',
|
|
'legal_review_state',
|
|
];
|
|
|
|
if ($actor && ! $actor->isAdmin() && collect($adminOnlyKeys)->contains(static fn (string $key): bool => array_key_exists($key, $attributes))) {
|
|
throw ValidationException::withMessages([
|
|
'partner_key' => 'Only admins can update partner or trust metadata.',
|
|
]);
|
|
}
|
|
|
|
$payload = [
|
|
'partner_key' => array_key_exists('partner_key', $attributes) ? ($attributes['partner_key'] ?: null) : $collection->partner_key,
|
|
'trust_tier' => array_key_exists('trust_tier', $attributes) ? ($attributes['trust_tier'] ?: null) : $collection->trust_tier,
|
|
'promotion_tier' => array_key_exists('promotion_tier', $attributes) ? ($attributes['promotion_tier'] ?: null) : $collection->promotion_tier,
|
|
'sponsorship_state' => array_key_exists('sponsorship_state', $attributes) ? ($attributes['sponsorship_state'] ?: null) : $collection->sponsorship_state,
|
|
'ownership_domain' => array_key_exists('ownership_domain', $attributes) ? ($attributes['ownership_domain'] ?: null) : $collection->ownership_domain,
|
|
'commercial_review_state' => array_key_exists('commercial_review_state', $attributes) ? ($attributes['commercial_review_state'] ?: null) : $collection->commercial_review_state,
|
|
'legal_review_state' => array_key_exists('legal_review_state', $attributes) ? ($attributes['legal_review_state'] ?: null) : $collection->legal_review_state,
|
|
];
|
|
|
|
$before = [
|
|
'partner_key' => $collection->partner_key,
|
|
'trust_tier' => $collection->trust_tier,
|
|
'promotion_tier' => $collection->promotion_tier,
|
|
'sponsorship_state' => $collection->sponsorship_state,
|
|
'ownership_domain' => $collection->ownership_domain,
|
|
'commercial_review_state' => $collection->commercial_review_state,
|
|
'legal_review_state' => $collection->legal_review_state,
|
|
];
|
|
|
|
$collection->forceFill($payload)->save();
|
|
$fresh = $collection->fresh();
|
|
|
|
app(CollectionHistoryService::class)->record(
|
|
$fresh,
|
|
$actor,
|
|
'partner_program_metadata_updated',
|
|
'Collection partner and governance metadata updated.',
|
|
$before,
|
|
$payload,
|
|
);
|
|
|
|
return $fresh;
|
|
}
|
|
|
|
public function publicLanding(string $programKey, int $limit = 18): array
|
|
{
|
|
$normalizedKey = trim($programKey);
|
|
|
|
if ($normalizedKey === '') {
|
|
return [
|
|
'program' => null,
|
|
'collections' => new EloquentCollection(),
|
|
'editorial_collections' => new EloquentCollection(),
|
|
'community_collections' => new EloquentCollection(),
|
|
'recent_collections' => new EloquentCollection(),
|
|
];
|
|
}
|
|
|
|
$baseQuery = Collection::query()
|
|
->public()
|
|
->where('program_key', $normalizedKey)
|
|
->where('placement_eligibility', true)
|
|
->with(['user:id,username,name', 'coverArtwork:id,user_id,title,slug,hash,thumb_ext,published_at,is_public,is_approved,deleted_at']);
|
|
|
|
$collections = (clone $baseQuery)
|
|
->orderByDesc('ranking_score')
|
|
->orderByDesc('health_score')
|
|
->limit(max(1, min($limit, 24)))
|
|
->get();
|
|
|
|
$leadCollection = $collections->first() ?: (clone $baseQuery)->first();
|
|
$partnerLabels = (clone $baseQuery)->whereNotNull('partner_label')->pluck('partner_label')->filter()->unique()->values()->all();
|
|
$sponsorshipLabels = (clone $baseQuery)->whereNotNull('sponsorship_label')->pluck('sponsorship_label')->filter()->unique()->values()->all();
|
|
|
|
return [
|
|
'program' => $leadCollection ? [
|
|
'key' => $normalizedKey,
|
|
'label' => $leadCollection->banner_text ?: $leadCollection->badge_label ?: Str::headline(str_replace(['_', '-'], ' ', $normalizedKey)),
|
|
'description' => $leadCollection->summary
|
|
?: $leadCollection->description
|
|
?: sprintf('Public collections grouped under the %s program, prepared for discovery, partner, and editorial surfaces.', Str::headline(str_replace(['_', '-'], ' ', $normalizedKey))),
|
|
'promotion_tier' => $leadCollection->promotion_tier,
|
|
'partner_labels' => $partnerLabels,
|
|
'sponsorship_labels' => $sponsorshipLabels,
|
|
'trust_tier' => $leadCollection->trust_tier,
|
|
'collections_count' => (clone $baseQuery)->count(),
|
|
] : null,
|
|
'collections' => $collections,
|
|
'editorial_collections' => (clone $baseQuery)->where('type', Collection::TYPE_EDITORIAL)->orderByDesc('ranking_score')->limit(6)->get(),
|
|
'community_collections' => (clone $baseQuery)->where('type', Collection::TYPE_COMMUNITY)->orderByDesc('ranking_score')->limit(6)->get(),
|
|
'recent_collections' => (clone $baseQuery)->latest('published_at')->limit(6)->get(),
|
|
];
|
|
}
|
|
} |