Commit workspace changes
This commit is contained in:
@@ -15,6 +15,7 @@ use App\Events\Collections\CollectionUpdated;
|
||||
use App\Events\Collections\SmartCollectionRulesUpdated;
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Collection;
|
||||
use App\Models\Group;
|
||||
use App\Models\User;
|
||||
use App\Support\AvatarUrl;
|
||||
use App\Services\ThumbnailPresenter;
|
||||
@@ -31,6 +32,7 @@ class CollectionService
|
||||
public function __construct(
|
||||
private readonly SmartCollectionService $smartCollections,
|
||||
private readonly CollectionCollaborationService $collaborators,
|
||||
private readonly GroupMembershipService $groupMembers,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -39,14 +41,14 @@ class CollectionService
|
||||
return $this->normalizeLayoutModules(null, Collection::TYPE_PERSONAL, true, false);
|
||||
}
|
||||
|
||||
public function makeUniqueSlugForUser(User $user, string $source, ?int $ignoreCollectionId = null): string
|
||||
public function makeUniqueSlugForUser(User $user, string $source, ?int $ignoreCollectionId = null, ?Group $group = null): string
|
||||
{
|
||||
$base = Str::slug(Str::limit($source, 140, ''));
|
||||
$base = $base !== '' ? $base : 'collection';
|
||||
$slug = $base;
|
||||
$suffix = 2;
|
||||
|
||||
while ($this->slugExistsForUser($user, $slug, $ignoreCollectionId)) {
|
||||
while ($this->slugExistsForUser($user, $slug, $ignoreCollectionId, $group)) {
|
||||
$slug = Str::limit($base, 132, '');
|
||||
$slug = rtrim($slug, '-');
|
||||
$slug .= '-' . $suffix;
|
||||
@@ -70,9 +72,10 @@ class CollectionService
|
||||
|
||||
$collection = new Collection();
|
||||
$collection->user()->associate($ownership['owner_user']);
|
||||
$collection->group()->associate($ownership['group']);
|
||||
$collection->managed_by_user_id = $ownership['managed_by_user_id'];
|
||||
$collection->title = (string) $attributes['title'];
|
||||
$collection->slug = $this->makeUniqueSlugForUser($ownership['owner_user'], (string) ($attributes['slug'] ?? $attributes['title']));
|
||||
$collection->slug = $this->makeUniqueSlugForUser($ownership['owner_user'], (string) ($attributes['slug'] ?? $attributes['title']), null, $ownership['group']);
|
||||
$collection->lifecycle_state = (string) ($attributes['lifecycle_state'] ?? Collection::LIFECYCLE_DRAFT);
|
||||
$collection->type = $type;
|
||||
$collection->editorial_owner_mode = $ownership['editorial_owner_mode'];
|
||||
@@ -129,7 +132,7 @@ class CollectionService
|
||||
$collection->collaborators_count = 1;
|
||||
$collection->smart_rules_json = $smartRules;
|
||||
$collection->layout_modules_json = $this->normalizeLayoutModules($attributes['layout_modules_json'] ?? null, $type, $allowComments, $allowSubmissions, false);
|
||||
$collection->profile_order = $this->nextProfileOrder($ownership['owner_user']);
|
||||
$collection->profile_order = $this->nextProfileOrder($ownership['owner_user'], $ownership['group']);
|
||||
$collection->last_activity_at = now();
|
||||
$collection->published_at = $this->resolvePublishedAt($attributes);
|
||||
$collection->unpublished_at = $this->resolveUnpublishedAt($attributes);
|
||||
@@ -179,10 +182,11 @@ class CollectionService
|
||||
$allowComments = array_key_exists('allow_comments', $attributes) ? (bool) $attributes['allow_comments'] : $collection->allow_comments;
|
||||
|
||||
$collection->user()->associate($ownership['owner_user']);
|
||||
$collection->group()->associate($ownership['group']);
|
||||
|
||||
$collection->fill([
|
||||
'title' => (string) ($attributes['title'] ?? $collection->title),
|
||||
'slug' => $this->makeUniqueSlugForUser($ownership['owner_user'], $slugSource, (int) $collection->id),
|
||||
'slug' => $this->makeUniqueSlugForUser($ownership['owner_user'], $slugSource, (int) $collection->id, $ownership['group']),
|
||||
'lifecycle_state' => (string) ($attributes['lifecycle_state'] ?? $collection->lifecycle_state),
|
||||
'type' => $type,
|
||||
'managed_by_user_id' => $ownership['managed_by_user_id'],
|
||||
@@ -541,7 +545,11 @@ class CollectionService
|
||||
->with(['contentType:id,slug,name']);
|
||||
},
|
||||
])
|
||||
->whereIn('user_id', $this->contributorIds($collection))
|
||||
->when(
|
||||
(int) ($collection->group_id ?? 0) > 0,
|
||||
fn ($builder) => $builder->where('group_id', (int) $collection->group_id),
|
||||
fn ($builder) => $builder->whereIn('user_id', $this->contributorIds($collection))
|
||||
)
|
||||
->whereNull('deleted_at')
|
||||
->whereNotIn('id', $attachedIds)
|
||||
->orderByDesc('published_at')
|
||||
@@ -560,17 +568,31 @@ class CollectionService
|
||||
|
||||
public function getCollectionOptionsForArtwork(User $owner, Artwork $artwork): array
|
||||
{
|
||||
if ((int) $artwork->user_id !== (int) $owner->id) {
|
||||
$isPersonalArtwork = (int) ($artwork->group_id ?? 0) < 1;
|
||||
$group = $artwork->group;
|
||||
|
||||
if ($isPersonalArtwork && (int) $artwork->user_id !== (int) $owner->id) {
|
||||
throw ValidationException::withMessages([
|
||||
'artwork_id' => 'You can only manage collections for your own artworks.',
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $isPersonalArtwork && (! $group || ! $group->canManageCollections($owner))) {
|
||||
throw ValidationException::withMessages([
|
||||
'artwork_id' => 'You can only manage collections for groups you can edit.',
|
||||
]);
|
||||
}
|
||||
|
||||
$collections = Collection::query()
|
||||
->ownedBy((int) $owner->id)
|
||||
->with('group')
|
||||
->when(
|
||||
! $isPersonalArtwork,
|
||||
fn ($query) => $query->where('group_id', (int) $artwork->group_id),
|
||||
fn ($query) => $query->ownedBy((int) $owner->id)
|
||||
)
|
||||
->where('mode', Collection::MODE_MANUAL)
|
||||
->orderByDesc('updated_at')
|
||||
->get(['id', 'user_id', 'title', 'slug', 'visibility', 'mode', 'artworks_count', 'updated_at']);
|
||||
->get(['id', 'user_id', 'group_id', 'title', 'slug', 'visibility', 'mode', 'artworks_count', 'updated_at']);
|
||||
|
||||
if ($collections->isEmpty()) {
|
||||
return [];
|
||||
@@ -586,6 +608,11 @@ class CollectionService
|
||||
return $collections->map(function (Collection $collection) use ($attachedCollectionIds, $owner) {
|
||||
$alreadyAttached = in_array((int) $collection->id, $attachedCollectionIds, true);
|
||||
|
||||
$publicUrl = route('profile.collections.show', [
|
||||
'username' => strtolower((string) $owner->username),
|
||||
'slug' => $collection->slug,
|
||||
]);
|
||||
|
||||
return [
|
||||
'id' => (int) $collection->id,
|
||||
'title' => (string) $collection->title,
|
||||
@@ -597,10 +624,7 @@ class CollectionService
|
||||
'already_attached' => $alreadyAttached,
|
||||
'attach_url' => route('settings.collections.artworks.attach', ['collection' => $collection->id]),
|
||||
'manage_url' => route('settings.collections.show', ['collection' => $collection->id]),
|
||||
'public_url' => route('profile.collections.show', [
|
||||
'username' => strtolower((string) $owner->username),
|
||||
'slug' => $collection->slug,
|
||||
]),
|
||||
'public_url' => $publicUrl,
|
||||
];
|
||||
})->all();
|
||||
}
|
||||
@@ -1319,13 +1343,19 @@ class CollectionService
|
||||
private function resolveOwnershipContext(User $actor, array $attributes, ?Collection $collection, string $type): array
|
||||
{
|
||||
if ($type !== Collection::TYPE_EDITORIAL) {
|
||||
$group = $this->resolveGroupContext($actor, $attributes, $collection);
|
||||
$ownerUser = $collection && ! $collection->hasSystemEditorialOwner() && (int) $collection->user_id !== (int) $actor->id
|
||||
? $collection->user
|
||||
: $actor;
|
||||
: ($group?->owner ?: $actor);
|
||||
|
||||
$managedByUserId = $group && (int) $ownerUser->id !== (int) $actor->id
|
||||
? (int) $actor->id
|
||||
: null;
|
||||
|
||||
return [
|
||||
'owner_user' => $ownerUser,
|
||||
'managed_by_user_id' => null,
|
||||
'group' => $group,
|
||||
'managed_by_user_id' => $managedByUserId,
|
||||
'editorial_owner_mode' => Collection::EDITORIAL_OWNER_CREATOR,
|
||||
'editorial_owner_user_id' => null,
|
||||
'editorial_owner_label' => null,
|
||||
@@ -1371,6 +1401,7 @@ class CollectionService
|
||||
|
||||
return [
|
||||
'owner_user' => $ownerUser,
|
||||
'group' => null,
|
||||
'managed_by_user_id' => $managedByUserId,
|
||||
'editorial_owner_mode' => $ownerMode,
|
||||
'editorial_owner_user_id' => $editorialOwnerUserId,
|
||||
@@ -1380,6 +1411,26 @@ class CollectionService
|
||||
|
||||
private function mapCollectionOwnerPayload(Collection $collection): array
|
||||
{
|
||||
if ((int) ($collection->group_id ?? 0) > 0) {
|
||||
$group = $collection->relationLoaded('group') ? $collection->group : $collection->group()->with('owner.profile')->first();
|
||||
|
||||
return [
|
||||
'name' => $group?->name ?: 'Skinbase Group',
|
||||
'username' => null,
|
||||
'profile_url' => $group ? $group->publicUrl() : null,
|
||||
'is_system' => false,
|
||||
'mode' => 'group',
|
||||
'managed_by_user_id' => $collection->managed_by_user_id ? (int) $collection->managed_by_user_id : null,
|
||||
'avatar_url' => $group?->avatarUrl(),
|
||||
'group' => $group ? [
|
||||
'id' => (int) $group->id,
|
||||
'slug' => (string) $group->slug,
|
||||
'name' => (string) $group->name,
|
||||
'public_url' => $group->publicUrl(),
|
||||
] : null,
|
||||
];
|
||||
}
|
||||
|
||||
$owner = $collection->relationLoaded('user') ? $collection->user : $collection->user()->first();
|
||||
$username = $collection->displayOwnerUsername();
|
||||
$avatarUrl = null;
|
||||
@@ -1396,6 +1447,7 @@ class CollectionService
|
||||
'mode' => $collection->editorial_owner_mode,
|
||||
'managed_by_user_id' => $collection->managed_by_user_id ? (int) $collection->managed_by_user_id : null,
|
||||
'avatar_url' => $avatarUrl,
|
||||
'group' => null,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1406,10 +1458,13 @@ class CollectionService
|
||||
return $presented['url'] ?? $artwork->thumbUrl('md');
|
||||
}
|
||||
|
||||
private function slugExistsForUser(User $user, string $slug, ?int $ignoreCollectionId = null): bool
|
||||
private function slugExistsForUser(User $user, string $slug, ?int $ignoreCollectionId = null, ?Group $group = null): bool
|
||||
{
|
||||
return Collection::query()
|
||||
->where('user_id', $user->id)
|
||||
->when($group !== null,
|
||||
fn ($query) => $query->where('group_id', $group->id),
|
||||
fn ($query) => $query->whereNull('group_id')->where('user_id', $user->id)
|
||||
)
|
||||
->where('slug', $slug)
|
||||
->when($ignoreCollectionId !== null, fn ($query) => $query->where('id', '!=', $ignoreCollectionId))
|
||||
->withTrashed()
|
||||
@@ -1421,13 +1476,37 @@ class CollectionService
|
||||
return max(1, (int) config('collections.featured_limit', 3));
|
||||
}
|
||||
|
||||
private function nextProfileOrder(User $user): int
|
||||
private function nextProfileOrder(User $user, ?Group $group = null): int
|
||||
{
|
||||
return (int) (Collection::query()
|
||||
->ownedBy((int) $user->id)
|
||||
->when($group !== null,
|
||||
fn ($query) => $query->where('group_id', $group->id),
|
||||
fn ($query) => $query->ownedBy((int) $user->id)
|
||||
)
|
||||
->max('profile_order') ?? -1) + 1;
|
||||
}
|
||||
|
||||
private function resolveGroupContext(User $actor, array $attributes, ?Collection $collection = null): ?Group
|
||||
{
|
||||
$groupIdentifier = $attributes['group'] ?? $attributes['group_id'] ?? ($collection?->group_id ? (string) $collection->group_id : null);
|
||||
|
||||
if ($groupIdentifier === null || $groupIdentifier === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$group = is_numeric($groupIdentifier)
|
||||
? Group::query()->with('members')->findOrFail((int) $groupIdentifier)
|
||||
: Group::query()->with('members')->where('slug', (string) $groupIdentifier)->firstOrFail();
|
||||
|
||||
if (! $group->canManageCollections($actor) && ! $actor->isAdmin()) {
|
||||
throw ValidationException::withMessages([
|
||||
'group' => 'You are not allowed to manage collections for this group.',
|
||||
]);
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
private function resolvePublishedAt(array $attributes, mixed $fallback = null): ?Carbon
|
||||
{
|
||||
if (! array_key_exists('published_at', $attributes)) {
|
||||
@@ -1463,6 +1542,12 @@ class CollectionService
|
||||
*/
|
||||
private function contributorIds(Collection $collection): array
|
||||
{
|
||||
if ((int) ($collection->group_id ?? 0) > 0) {
|
||||
$group = $collection->relationLoaded('group') ? $collection->group : $collection->group()->with('members')->first();
|
||||
|
||||
return $group ? $this->groupMembers->activeContributorIds($group) : [];
|
||||
}
|
||||
|
||||
return $collection->isCollaborative()
|
||||
? $this->collaborators->activeContributorIds($collection)
|
||||
: [(int) $collection->user_id];
|
||||
|
||||
Reference in New Issue
Block a user