feat: ship creator journey v2 and profile updates
This commit is contained in:
@@ -17,6 +17,7 @@ use App\Models\Artwork;
|
||||
use App\Models\Collection;
|
||||
use App\Models\Group;
|
||||
use App\Models\User;
|
||||
use App\Services\Maturity\ArtworkMaturityService;
|
||||
use App\Support\AvatarUrl;
|
||||
use App\Services\ThumbnailPresenter;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
@@ -33,6 +34,7 @@ class CollectionService
|
||||
private readonly SmartCollectionService $smartCollections,
|
||||
private readonly CollectionCollaborationService $collaborators,
|
||||
private readonly GroupMembershipService $groupMembers,
|
||||
private readonly ArtworkMaturityService $maturity,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -492,12 +494,14 @@ class CollectionService
|
||||
return $query->get();
|
||||
}
|
||||
|
||||
public function getCollectionDetailArtworks(Collection $collection, bool $ownerView, int $perPage = 24): LengthAwarePaginator
|
||||
public function getCollectionDetailArtworks(Collection $collection, bool $ownerView, int $perPage = 24, ?User $viewer = null): LengthAwarePaginator
|
||||
{
|
||||
if ($collection->isSmart()) {
|
||||
return $this->smartCollections->resolveArtworks($collection, $ownerView, $perPage);
|
||||
}
|
||||
|
||||
$viewer ??= $ownerView ? null : request()->user();
|
||||
|
||||
$query = $collection->artworks()
|
||||
->with([
|
||||
'user:id,name,username',
|
||||
@@ -515,12 +519,21 @@ class CollectionService
|
||||
->where('artworks.is_approved', true)
|
||||
->whereNotNull('artworks.published_at')
|
||||
->where('artworks.published_at', '<=', now());
|
||||
|
||||
if ($this->viewerShouldHideMature($viewer)) {
|
||||
$query->whereRaw('COALESCE(artworks.is_mature, 0) = 0')
|
||||
->whereRaw("COALESCE(artworks.maturity_status, 'clear') != ?", [ArtworkMaturityService::STATUS_SUSPECTED]);
|
||||
}
|
||||
}
|
||||
|
||||
$query = match ($collection->sort_mode) {
|
||||
Collection::SORT_NEWEST => $query->orderByDesc('artworks.published_at'),
|
||||
Collection::SORT_OLDEST => $query->orderBy('artworks.published_at'),
|
||||
Collection::SORT_POPULAR => $query->orderByDesc('artworks.view_count')->orderByPivot('order_num'),
|
||||
Collection::SORT_POPULAR => $query
|
||||
->leftJoin('artwork_stats as artwork_stats_sort', 'artwork_stats_sort.artwork_id', '=', 'artworks.id')
|
||||
->reorder()
|
||||
->orderByRaw('COALESCE(artwork_stats_sort.views, 0) DESC')
|
||||
->orderBy('collection_artwork.order_num'),
|
||||
default => $query->orderByPivot('order_num'),
|
||||
};
|
||||
|
||||
@@ -843,15 +856,18 @@ class CollectionService
|
||||
|
||||
public function mapCollectionCardPayloads(iterable $collections, bool $ownerView = false, ?User $viewer = null): array
|
||||
{
|
||||
$viewer ??= $ownerView ? null : request()->user();
|
||||
$collectionList = $collections instanceof EloquentCollection
|
||||
? $collections
|
||||
: new EloquentCollection(is_array($collections) ? $collections : iterator_to_array($collections));
|
||||
|
||||
$collectionIds = $collectionList->pluck('id')->map(static fn ($id) => (int) $id)->all();
|
||||
$hideMatureCovers = ! $ownerView && $this->viewerShouldHideMature($viewer);
|
||||
|
||||
$firstArtworkMap = $this->firstArtworkMapForCollections(
|
||||
$collectionIds,
|
||||
! $ownerView
|
||||
! $ownerView,
|
||||
$hideMatureCovers,
|
||||
);
|
||||
|
||||
$savedCollectionIds = $viewer && ! $ownerView && $collectionIds !== []
|
||||
@@ -866,9 +882,11 @@ class CollectionService
|
||||
return $collectionList->map(function (Collection $collection) use ($ownerView, $viewer, $firstArtworkMap, $savedCollectionIds) {
|
||||
$resolvedCover = $collection->isSmart()
|
||||
? $this->smartCollections->firstArtwork($collection, $ownerView)
|
||||
: $collection->resolvedCoverArtwork(! $ownerView);
|
||||
: $collection->resolvedCoverArtwork(! $ownerView, ! $ownerView && $this->viewerShouldHideMature($viewer));
|
||||
$fallbackCover = $firstArtworkMap->get((int) $collection->id);
|
||||
$cover = $resolvedCover ?? $fallbackCover;
|
||||
$cover = $this->eligibleCoverArtwork($resolvedCover, ! $ownerView, ! $ownerView && $this->viewerShouldHideMature($viewer))
|
||||
? $resolvedCover
|
||||
: $fallbackCover;
|
||||
$summary = $collection->summary ?? $collection->description;
|
||||
$isSaved = in_array((int) $collection->id, $savedCollectionIds, true);
|
||||
$canSave = ! $ownerView && $viewer && $collection->canBeSavedBy($viewer);
|
||||
@@ -958,6 +976,7 @@ class CollectionService
|
||||
'last_recommendation_refresh_at' => optional($collection->last_recommendation_refresh_at)?->toISOString(),
|
||||
'smart_summary' => $collection->isSmart() ? $this->smartCollections->smartSummary($collection->smart_rules_json) : null,
|
||||
'cover_image' => $cover ? $this->mapArtworkThumb($cover) : null,
|
||||
'cover_image_maturity' => ! $ownerView && $cover ? $this->maturity->presentation($cover, $viewer) : null,
|
||||
'cover_artwork_id' => $cover?->id,
|
||||
'saved' => $isSaved,
|
||||
'save_url' => $canSave ? route('collections.save', ['collection' => $collection->id]) : null,
|
||||
@@ -976,11 +995,18 @@ class CollectionService
|
||||
})->all();
|
||||
}
|
||||
|
||||
public function mapCollectionDetailPayload(Collection $collection, bool $ownerView = false): array
|
||||
public function mapCollectionDetailPayload(Collection $collection, bool $ownerView = false, ?User $viewer = null): array
|
||||
{
|
||||
$viewer ??= $ownerView ? null : request()->user();
|
||||
$hideMatureCovers = ! $ownerView && $this->viewerShouldHideMature($viewer);
|
||||
$cover = $collection->isSmart()
|
||||
? $this->smartCollections->firstArtwork($collection, $ownerView)
|
||||
: $collection->resolvedCoverArtwork(! $ownerView);
|
||||
: $collection->resolvedCoverArtwork(! $ownerView, $hideMatureCovers);
|
||||
|
||||
if (! $this->eligibleCoverArtwork($cover, ! $ownerView, $hideMatureCovers)) {
|
||||
$cover = $this->firstArtworkMapForCollections([(int) $collection->id], ! $ownerView, $hideMatureCovers)
|
||||
->get((int) $collection->id);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $collection->id,
|
||||
@@ -1074,7 +1100,8 @@ class CollectionService
|
||||
'expired_at' => optional($collection->expired_at)?->toISOString(),
|
||||
'history_count' => (int) $collection->history_count,
|
||||
'cover_image' => $cover ? $this->mapArtworkThumb($cover) : null,
|
||||
'cover_artwork_id' => $collection->cover_artwork_id,
|
||||
'cover_image_maturity' => ! $ownerView && $cover ? $this->maturity->presentation($cover, $viewer) : null,
|
||||
'cover_artwork_id' => $cover?->id,
|
||||
'smart_rules_json' => $collection->smart_rules_json,
|
||||
'layout_modules' => $this->normalizeLayoutModules($collection->layout_modules_json, $collection->type, (bool) $collection->allow_comments, (bool) $collection->allow_submissions),
|
||||
'smart_summary' => $collection->isSmart() ? $this->smartCollections->smartSummary($collection->smart_rules_json) : null,
|
||||
@@ -1194,7 +1221,7 @@ class CollectionService
|
||||
* @param array<int, int> $collectionIds
|
||||
* @return SupportCollection<int, Artwork>
|
||||
*/
|
||||
private function firstArtworkMapForCollections(array $collectionIds, bool $publicOnly): SupportCollection
|
||||
private function firstArtworkMapForCollections(array $collectionIds, bool $publicOnly, bool $hideMature = false): SupportCollection
|
||||
{
|
||||
if ($collectionIds === []) {
|
||||
return collect();
|
||||
@@ -1210,6 +1237,10 @@ class CollectionService
|
||||
->whereNotNull('a.published_at')
|
||||
->where('a.published_at', '<=', now());
|
||||
})
|
||||
->when($hideMature, function ($query): void {
|
||||
$query->whereRaw('COALESCE(a.is_mature, 0) = 0')
|
||||
->whereRaw("COALESCE(a.maturity_status, 'clear') != ?", ['suspected']);
|
||||
})
|
||||
->orderBy('ca.collection_id')
|
||||
->orderBy('ca.order_num')
|
||||
->select(['ca.collection_id', 'a.id'])
|
||||
@@ -1237,7 +1268,7 @@ class CollectionService
|
||||
$contentType = $category?->contentType;
|
||||
$stats = $artwork->stats;
|
||||
|
||||
return array_merge([
|
||||
return $this->maturity->decoratePayload(array_merge([
|
||||
'id' => $artwork->id,
|
||||
'title' => $artwork->title,
|
||||
'slug' => $artwork->slug,
|
||||
@@ -1261,7 +1292,7 @@ class CollectionService
|
||||
'username' => $artwork->user->username,
|
||||
'profile_url' => route('profile.show', ['username' => strtolower((string) $artwork->user->username)]),
|
||||
] : null,
|
||||
], $extra);
|
||||
], $extra), $artwork, request()->user());
|
||||
}
|
||||
|
||||
private function normalizeLayoutModules(?array $modules, string $type, bool $allowComments, bool $allowSubmissions, bool $includePresentation = true): array
|
||||
@@ -1458,6 +1489,29 @@ class CollectionService
|
||||
return $presented['url'] ?? $artwork->thumbUrl('md');
|
||||
}
|
||||
|
||||
private function eligibleCoverArtwork(?Artwork $artwork, bool $publicOnly, bool $hideMature): bool
|
||||
{
|
||||
if (! $artwork) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($publicOnly && (! (bool) $artwork->is_public || ! (bool) $artwork->is_approved || $artwork->published_at === null || $artwork->published_at->gt(now()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $hideMature) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ! (bool) $artwork->is_mature
|
||||
&& (string) ($artwork->maturity_status ?? ArtworkMaturityService::STATUS_CLEAR) !== ArtworkMaturityService::STATUS_SUSPECTED;
|
||||
}
|
||||
|
||||
private function viewerShouldHideMature(?User $viewer): bool
|
||||
{
|
||||
return $this->maturity->viewerPreferences($viewer)['visibility'] === ArtworkMaturityService::VIEW_HIDE;
|
||||
}
|
||||
|
||||
private function slugExistsForUser(User $user, string $slug, ?int $ignoreCollectionId = null, ?Group $group = null): bool
|
||||
{
|
||||
return Collection::query()
|
||||
|
||||
Reference in New Issue
Block a user