Collapse profile group contribution queries

This commit is contained in:
2026-08-30 07:58:38 +02:00
parent dba1f73e01
commit 7805baa17d
2 changed files with 256 additions and 30 deletions
+86 -30
View File
@@ -1499,7 +1499,7 @@ class ProfileController extends Controller
private function buildGroupContributionHistory(User $user): array
{
return GroupContributorStat::query()
$stats = GroupContributorStat::query()
->with(['group.owner.profile'])
->where('user_id', $user->id)
->whereHas('group', fn ($query) => $query
@@ -1508,29 +1508,60 @@ class ProfileController extends Controller
->orderByDesc('release_count')
->orderByDesc('credited_artworks_count')
->limit(8)
->get();
$groupIds = $stats->pluck('group_id')->map(static fn ($id): int => (int) $id)->values()->all();
if ($groupIds === []) {
return [];
}
$membershipsByGroup = GroupMember::query()
->whereIn('group_id', $groupIds)
->where('user_id', $user->id)
->where('status', Group::STATUS_ACTIVE)
->get()
->map(function (GroupContributorStat $stat) use ($user): ?array {
->keyBy('group_id');
$releaseRolesByGroup = GroupReleaseContributor::query()
->join('group_releases as bulk_releases', 'bulk_releases.id', '=', 'group_release_contributors.group_release_id')
->where('group_release_contributors.user_id', $user->id)
->whereIn('bulk_releases.group_id', $groupIds)
->whereNull('bulk_releases.deleted_at')
->orderBy('group_release_contributors.id')
->get([
'bulk_releases.group_id',
'group_release_contributors.role_label',
])
->groupBy('group_id');
$projectRolesByGroup = GroupProjectMember::query()
->join('group_projects as bulk_projects', 'bulk_projects.id', '=', 'group_project_members.group_project_id')
->where('group_project_members.user_id', $user->id)
->whereIn('bulk_projects.group_id', $groupIds)
->whereNull('bulk_projects.deleted_at')
->orderBy('group_project_members.id')
->get([
'bulk_projects.group_id',
'group_project_members.role_label',
])
->groupBy('group_id');
$recentReleasesByGroup = $this->loadRecentGroupReleaseTitles($user, $groupIds);
return $stats
->map(function (GroupContributorStat $stat) use ($user, $membershipsByGroup, $releaseRolesByGroup, $projectRolesByGroup, $recentReleasesByGroup): ?array {
$group = $stat->group;
if (! $group) {
return null;
}
$member = GroupMember::query()
->where('group_id', $group->id)
->where('user_id', $user->id)
->where('status', Group::STATUS_ACTIVE)
->first();
$groupId = (int) $group->id;
$member = $membershipsByGroup->get($groupId);
$roleLabels = collect()
->merge(GroupReleaseContributor::query()
->where('user_id', $user->id)
->whereHas('release', fn ($query) => $query->where('group_id', $group->id))
->pluck('role_label'))
->merge(GroupProjectMember::query()
->where('user_id', $user->id)
->whereHas('project', fn ($query) => $query->where('group_id', $group->id))
->pluck('role_label'))
->merge($releaseRolesByGroup->get($groupId, collect())->pluck('role_label'))
->merge($projectRolesByGroup->get($groupId, collect())->pluck('role_label'))
->filter()
->map(fn ($label): string => trim((string) $label))
->filter()
@@ -1538,21 +1569,7 @@ class ProfileController extends Controller
->values()
->all();
$recentReleaseTitles = GroupRelease::query()
->where('group_id', $group->id)
->where('visibility', GroupRelease::VISIBILITY_PUBLIC)
->where(function ($query) use ($user): void {
$query->where('lead_user_id', $user->id)
->orWhere('created_by_user_id', $user->id)
->orWhereHas('contributorLinks', fn ($contributorQuery) => $contributorQuery->where('user_id', $user->id));
})
->orderByDesc('released_at')
->latest('updated_at')
->limit(3)
->pluck('title')
->map(fn ($title): string => (string) $title)
->values()
->all();
$recentReleaseTitles = $recentReleasesByGroup->get($groupId, collect())->all();
$joinedAt = $group->isOwnedBy($user)
? $group->created_at?->toISOString()
@@ -1589,6 +1606,45 @@ class ProfileController extends Controller
->all();
}
/**
* Load the same top-three public releases per group as the previous
* per-group LIMIT query, while keeping the existing two-column ordering.
*
* @param array<int, int> $groupIds
* @return \Illuminate\Support\Collection<int, \Illuminate\Support\Collection<int, string>>
*/
private function loadRecentGroupReleaseTitles(User $user, array $groupIds): \Illuminate\Support\Collection
{
$eligibleReleases = GroupRelease::query()
->whereIn('group_id', $groupIds)
->where('visibility', GroupRelease::VISIBILITY_PUBLIC)
->where(function ($query) use ($user): void {
$query->where('lead_user_id', $user->id)
->orWhere('created_by_user_id', $user->id)
->orWhereHas('contributorLinks', fn ($contributorQuery) => $contributorQuery->where('user_id', $user->id));
})
->select(['id', 'group_id', 'title', 'released_at', 'updated_at']);
$ranked = DB::query()
->fromSub($eligibleReleases, 'eligible_group_releases')
->select([
'group_id',
'title',
'released_at',
'updated_at',
])
->selectRaw('ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY released_at DESC, updated_at DESC) as release_rank');
return DB::query()
->fromSub($ranked, 'ranked_group_releases')
->where('release_rank', '<=', 3)
->orderBy('group_id')
->orderBy('release_rank')
->get(['group_id', 'title'])
->groupBy('group_id')
->map(fn ($rows) => $rows->pluck('title')->map(fn ($title): string => (string) $title)->values());
}
private function resolveFavouriteTable(): ?string
{
foreach (['artwork_favourites', 'user_favorites', 'artworks_favourites', 'favourites'] as $table) {