chore: commit current workspace changes

This commit is contained in:
2026-05-02 09:37:14 +02:00
parent 79235133f0
commit caf1464aa5
121 changed files with 485218 additions and 181663 deletions

View File

@@ -0,0 +1,119 @@
<?php
use App\Models\Artwork;
use App\Models\ArtworkStats;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use Illuminate\Pagination\Cursor;
it('supports cursor pagination for latest profile artworks', function () {
[$user] = seedProfileArtworksApiFixtures(26);
$firstPage = $this->getJson("/api/profile/{$user->username}/artworks");
$firstPage->assertOk();
$firstPage->assertJsonCount(24, 'data');
$nextCursor = $firstPage->json('next_cursor');
expect($nextCursor)->not->toBeNull();
$secondPage = $this->getJson("/api/profile/{$user->username}/artworks?cursor={$nextCursor}");
$secondPage->assertOk();
$secondPage->assertJsonCount(2, 'data');
});
it('supports cursor pagination for stats-sorted profile artworks', function () {
[$user] = seedProfileArtworksApiFixtures(26);
$firstPage = $this->getJson("/api/profile/{$user->username}/artworks?sort=views");
$firstPage->assertOk();
$firstPage->assertJsonCount(24, 'data');
$nextCursor = $firstPage->json('next_cursor');
expect($nextCursor)->not->toBeNull();
$secondPage = $this->getJson("/api/profile/{$user->username}/artworks?sort=views&cursor={$nextCursor}");
$secondPage->assertOk();
$secondPage->assertJsonCount(2, 'data');
});
it('falls back to the first page when a legacy profile artworks cursor is missing id', function () {
[$user] = seedProfileArtworksApiFixtures(26);
$legacyCursor = new Cursor([
'published_at' => Artwork::query()->orderByDesc('published_at')->value('published_at')?->format(DATE_ATOM),
]);
$response = $this->getJson("/api/profile/{$user->username}/artworks?cursor={$legacyCursor->encode()}");
$response->assertOk();
$response->assertJsonCount(24, 'data');
expect($response->json('next_cursor'))->not->toBeNull();
});
function seedProfileArtworksApiFixtures(int $count): array
{
$user = User::factory()->create([
'name' => 'Profile Artist',
'username' => 'profileartist',
'email' => 'profileartist@example.test',
]);
$contentType = ContentType::create([
'name' => 'Skins',
'slug' => 'skins',
'description' => 'Skins content type',
]);
$category = Category::create([
'content_type_id' => $contentType->id,
'name' => 'Winamp',
'slug' => 'winamp',
'description' => 'Winamp skins',
'is_active' => true,
'sort_order' => 1,
]);
for ($i = 1; $i <= $count; $i++) {
$artwork = Artwork::factory()
->for($user)
->create([
'title' => 'Profile Artwork ' . $i,
'slug' => 'profile-artwork-' . $i,
'published_at' => now()->subMinutes($i),
]);
$artwork->categories()->attach($category->id);
ArtworkStats::create([
'artwork_id' => $artwork->id,
'views' => $count - $i,
'downloads' => $i,
'favorites' => $i,
'rating_avg' => 0,
'rating_count' => 0,
'comments_count' => 0,
'shares_count' => 0,
'ranking_score' => $count - $i,
'engagement_velocity' => 0,
'shares_24h' => 0,
'comments_24h' => 0,
'favourites_24h' => 0,
'heat_score' => $count - $i,
'heat_score_updated_at' => null,
'views_1h' => 0,
'favourites_1h' => 0,
'comments_1h' => 0,
'shares_1h' => 0,
'downloads_1h' => 0,
]);
}
return [$user, $contentType, $category];
}

View File

@@ -115,4 +115,15 @@ it('prioritizes higher-signal world rewards ahead of participation on profile re
->where('worldRewards.items.0.badge_label', 'Pixel Week 2026 Winner')
->where('worldRewards.items.1.badge_label', 'Retro Month 2026 Participant')
->where('worldRewards.recent.0.badge_label', 'Retro Month 2026 Participant'));
});
it('redirects public profile paths from stray skinbase subdomains to the canonical host', function (): void {
config()->set('app.url', 'https://skinbase.org');
User::factory()->create([
'username' => 'ta2027',
]);
$this->get('https://ffh84a.skinbase.org/@ta2027')
->assertRedirect('https://skinbase.org/@ta2027');
});