171 lines
6.0 KiB
PHP
171 lines
6.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Http\Controllers\User\ProfileController;
|
|
use App\Models\Group;
|
|
use App\Models\GroupContributorStat;
|
|
use App\Models\GroupMember;
|
|
use App\Models\GroupProject;
|
|
use App\Models\GroupProjectMember;
|
|
use App\Models\GroupRelease;
|
|
use App\Models\GroupReleaseContributor;
|
|
use App\Models\User;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
function invokeGroupContributionHistory(User $user): array
|
|
{
|
|
$method = new ReflectionMethod(ProfileController::class, 'buildGroupContributionHistory');
|
|
$method->setAccessible(true);
|
|
|
|
return $method->invoke(app(ProfileController::class), $user);
|
|
}
|
|
|
|
function makeGroupRelease(Group $group, User $creator, string $title, CarbonImmutable $releasedAt, string $visibility = GroupRelease::VISIBILITY_PUBLIC): GroupRelease
|
|
{
|
|
return GroupRelease::create([
|
|
'group_id' => $group->id,
|
|
'title' => $title,
|
|
'slug' => strtolower(str_replace(' ', '-', $title)) . '-' . uniqid(),
|
|
'status' => GroupRelease::STATUS_RELEASED,
|
|
'current_stage' => GroupRelease::STAGE_RELEASED,
|
|
'visibility' => $visibility,
|
|
'released_at' => $releasedAt,
|
|
'published_at' => $releasedAt,
|
|
'created_by_user_id' => $creator->id,
|
|
]);
|
|
}
|
|
|
|
it('preserves contribution output semantics while loading group data in bulk', function (): void {
|
|
$user = User::factory()->create();
|
|
$owner = User::factory()->create();
|
|
$group = Group::factory()->create([
|
|
'owner_user_id' => $owner->id,
|
|
'name' => 'Visible Contribution Group',
|
|
'slug' => 'visible-contribution-group-' . uniqid(),
|
|
]);
|
|
|
|
GroupContributorStat::create([
|
|
'group_id' => $group->id,
|
|
'user_id' => $user->id,
|
|
'credited_artworks_count' => 7,
|
|
'release_count' => 5,
|
|
'project_count' => 3,
|
|
'review_actions_count' => 2,
|
|
]);
|
|
GroupMember::create([
|
|
'group_id' => $group->id,
|
|
'user_id' => $user->id,
|
|
'role' => Group::ROLE_EDITOR,
|
|
'status' => Group::STATUS_ACTIVE,
|
|
]);
|
|
|
|
$project = GroupProject::create([
|
|
'group_id' => $group->id,
|
|
'title' => 'Visible Project',
|
|
'slug' => 'visible-project-' . uniqid(),
|
|
'status' => GroupProject::STATUS_ACTIVE,
|
|
'visibility' => GroupProject::VISIBILITY_PUBLIC,
|
|
'created_by_user_id' => $owner->id,
|
|
]);
|
|
GroupProjectMember::create([
|
|
'group_project_id' => $project->id,
|
|
'user_id' => $user->id,
|
|
'role_label' => 'Project Lead',
|
|
'is_lead' => true,
|
|
]);
|
|
|
|
$newest = makeGroupRelease($group, $user, 'Newest Release', CarbonImmutable::parse('2026-08-20 12:00:00'));
|
|
$middle = makeGroupRelease($group, $owner, 'Middle Release', CarbonImmutable::parse('2026-08-19 12:00:00'));
|
|
$oldest = makeGroupRelease($group, $owner, 'Oldest Release', CarbonImmutable::parse('2026-08-18 12:00:00'));
|
|
makeGroupRelease($group, $owner, 'Hidden Release', CarbonImmutable::parse('2026-08-21 12:00:00'), GroupRelease::VISIBILITY_PRIVATE);
|
|
GroupReleaseContributor::create([
|
|
'group_release_id' => $middle->id,
|
|
'user_id' => $user->id,
|
|
'role_label' => 'Release Contributor',
|
|
'sort_order' => 0,
|
|
]);
|
|
GroupReleaseContributor::create([
|
|
'group_release_id' => $oldest->id,
|
|
'user_id' => $user->id,
|
|
'role_label' => 'Project Lead',
|
|
'sort_order' => 1,
|
|
]);
|
|
|
|
$result = invokeGroupContributionHistory($user);
|
|
|
|
expect($result)->toHaveCount(1);
|
|
expect($result[0]['group'])->toMatchArray([
|
|
'id' => $group->id,
|
|
'name' => 'Visible Contribution Group',
|
|
'slug' => $group->slug,
|
|
]);
|
|
expect($result[0]['joined_at'])->toBeString();
|
|
expect($result[0]['counts'])->toBe([
|
|
'credited_artworks' => 7,
|
|
'releases' => 5,
|
|
'projects' => 3,
|
|
'review_actions' => 2,
|
|
]);
|
|
expect($result[0]['role_labels'])->toBe(['Release Contributor', 'Project Lead']);
|
|
expect($result[0]['recent_release_titles'])->toBe(['Newest Release', 'Middle Release', 'Oldest Release']);
|
|
expect($result[0]['role'])->toBe(Group::ROLE_EDITOR);
|
|
expect($result[0]['trusted_indicator'])->toBeFalse();
|
|
});
|
|
|
|
it('keeps public visibility filtering and owner role semantics', function (): void {
|
|
$user = User::factory()->create();
|
|
$ownerGroup = Group::factory()->create([
|
|
'owner_user_id' => $user->id,
|
|
'slug' => 'owner-contribution-group-' . uniqid(),
|
|
]);
|
|
$privateGroup = Group::factory()->private()->create([
|
|
'slug' => 'private-contribution-group-' . uniqid(),
|
|
]);
|
|
|
|
GroupContributorStat::create(['group_id' => $ownerGroup->id, 'user_id' => $user->id]);
|
|
GroupContributorStat::create(['group_id' => $privateGroup->id, 'user_id' => $user->id, 'release_count' => 99]);
|
|
|
|
$result = invokeGroupContributionHistory($user);
|
|
|
|
expect($result)->toHaveCount(1)
|
|
->and($result[0]['group']['id'])->toBe($ownerGroup->id)
|
|
->and($result[0]['role'])->toBe(Group::ROLE_OWNER)
|
|
->and($result[0]['joined_at'])->toBeString();
|
|
});
|
|
|
|
it('keeps contribution-history query count bounded as group count grows', function (): void {
|
|
$counts = [];
|
|
|
|
foreach ([0, 1, 2, 4, 8] as $groupCount) {
|
|
$user = User::factory()->create();
|
|
|
|
for ($index = 0; $index < $groupCount; $index++) {
|
|
$group = Group::factory()->create([
|
|
'slug' => 'query-count-group-' . $groupCount . '-' . $index . '-' . uniqid(),
|
|
]);
|
|
GroupContributorStat::create([
|
|
'group_id' => $group->id,
|
|
'user_id' => $user->id,
|
|
'credited_artworks_count' => $groupCount - $index,
|
|
'release_count' => $groupCount - $index,
|
|
]);
|
|
}
|
|
|
|
DB::flushQueryLog();
|
|
DB::enableQueryLog();
|
|
invokeGroupContributionHistory($user);
|
|
$counts[$groupCount] = count(DB::getQueryLog());
|
|
DB::disableQueryLog();
|
|
}
|
|
|
|
expect($counts)->toBe([
|
|
0 => 1,
|
|
1 => 8,
|
|
2 => 8,
|
|
4 => 8,
|
|
8 => 8,
|
|
]);
|
|
});
|