feat: ship creator journey v2 and profile updates

This commit is contained in:
2026-04-12 21:42:07 +02:00
parent a2457f4e49
commit d5cff21ea2
335 changed files with 20147 additions and 1545 deletions

View File

@@ -0,0 +1,186 @@
<?php
declare(strict_types=1);
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Klevze\ControlPanel\Models\Admin\AdminVerification;
uses(RefreshDatabase::class);
function createArtworkBrowserAdmin(): User
{
$admin = User::factory()->create(['role' => 'admin']);
$admin->forceFill([
'isAdmin' => true,
'activated' => true,
])->save();
AdminVerification::createForUser($admin->fresh());
return $admin->fresh();
}
it('remembers the selected content type and root scope on the categories browser', function (): void {
$admin = createArtworkBrowserAdmin();
$skins = ContentType::query()->create([
'name' => 'Skins',
'slug' => 'skins',
'description' => 'Skin uploads',
'order' => 1,
]);
$wallpapers = ContentType::query()->create([
'name' => 'Wallpapers',
'slug' => 'wallpapers',
'description' => 'Wallpaper uploads',
'order' => 2,
]);
$selectedRoot = Category::query()->create([
'content_type_id' => $skins->id,
'parent_id' => null,
'name' => 'Skins Root Selected',
'slug' => 'skins-root-selected',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
Category::query()->create([
'content_type_id' => $skins->id,
'parent_id' => $selectedRoot->id,
'name' => 'Skin Child Alpha',
'slug' => 'skin-child-alpha',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
Category::query()->create([
'content_type_id' => $skins->id,
'parent_id' => $selectedRoot->id,
'name' => 'Skin Child Beta',
'slug' => 'skin-child-beta',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 2,
]);
Category::query()->create([
'content_type_id' => $wallpapers->id,
'parent_id' => null,
'name' => 'Wallpaper Root Hidden',
'slug' => 'wallpaper-root-hidden',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
$response = $this->actingAs($admin)->actingAs($admin, 'controlpanel')
->get(route('admin.cp.artworks.categories.main', [
'content_type_id' => $skins->id,
'root_category_id' => $selectedRoot->id,
]));
$response->assertOk()
->assertSessionHas('cp.artworks.categories.filters.content_type_id', (string) $skins->id)
->assertSessionHas('cp.artworks.categories.filters.root_category_id', (string) $selectedRoot->id)
->assertSee('Subcategories of Skins Root Selected')
->assertSee('Skin Child Alpha')
->assertSee('Skin Child Beta')
->assertDontSee('Wallpaper Root Hidden');
});
it('reorders only the currently selected sibling level', function (): void {
$admin = createArtworkBrowserAdmin();
$contentType = ContentType::query()->create([
'name' => 'Skins',
'slug' => 'skins',
'description' => 'Skin uploads',
'order' => 1,
]);
$firstRoot = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => null,
'name' => 'First Root',
'slug' => 'first-root',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
$secondRoot = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => null,
'name' => 'Second Root',
'slug' => 'second-root',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 2,
]);
$childOne = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => $firstRoot->id,
'name' => 'Child One',
'slug' => 'child-one',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
$childTwo = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => $firstRoot->id,
'name' => 'Child Two',
'slug' => 'child-two',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 2,
]);
$otherBranchChild = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => $secondRoot->id,
'name' => 'Other Branch Child',
'slug' => 'other-branch-child',
'description' => null,
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
$this->actingAs($admin)->actingAs($admin, 'controlpanel')
->postJson(route('admin.cp.artworks.categories.reorder-tree'), [
'content_type_id' => $contentType->id,
'parent_id' => $firstRoot->id,
'data' => [
['id' => $childTwo->id],
['id' => $childOne->id],
],
])
->assertOk()
->assertJson([
'status' => 200,
'message' => 'Category order updated.',
]);
expect($childOne->fresh()->sort_order)->toBe(2)
->and($childTwo->fresh()->sort_order)->toBe(1)
->and($otherBranchChild->fresh()->sort_order)->toBe(1)
->and($otherBranchChild->fresh()->parent_id)->toBe($secondRoot->id);
});

View File

@@ -0,0 +1,104 @@
<?php
declare(strict_types=1);
use App\Models\Category;
use App\Models\ContentType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Klevze\ControlPanel\Models\Admin\AdminVerification;
uses(RefreshDatabase::class);
function createArtworkTaxonomyAdmin(): User
{
$admin = User::factory()->create(['role' => 'admin']);
$admin->forceFill([
'isAdmin' => true,
'activated' => true,
])->save();
AdminVerification::createForUser($admin->fresh());
return $admin->fresh();
}
it('stores plain ampersands when categories are updated in control panel', function (): void {
$admin = createArtworkTaxonomyAdmin();
$contentType = ContentType::query()->create([
'name' => 'Digital Art',
'slug' => 'digital-art',
'description' => 'Digital art uploads',
'order' => 1,
]);
$category = Category::query()->create([
'content_type_id' => $contentType->id,
'parent_id' => null,
'name' => 'Anime',
'slug' => 'anime',
'description' => 'Initial description',
'image' => null,
'is_active' => true,
'sort_order' => 1,
]);
$this->actingAs($admin)->actingAs($admin, 'controlpanel')
->post(route('admin.cp.artworks.categories.update', $category->id), [
'content_type_id' => $contentType->id,
'parent_id' => '',
'name' => 'Anime & Manga',
'slug' => 'anime',
'description' => 'Anime & Manga artwork',
'image' => '',
'sort_order' => 1,
'is_active' => '1',
])
->assertRedirect(route('admin.cp.artworks.categories.main'));
$category->refresh();
expect(DB::table('categories')->where('id', $category->id)->value('name'))->toBe('Anime & Manga')
->and(DB::table('categories')->where('id', $category->id)->value('description'))->toBe('Anime & Manga artwork')
->and($category->name)->toBe('Anime & Manga')
->and($category->description)->toBe('Anime & Manga artwork');
});
it('renders legacy encoded category names decoded in control panel edit form', function (): void {
$admin = createArtworkTaxonomyAdmin();
$contentTypeId = DB::table('content_types')->insertGetId([
'name' => 'Digital Art',
'slug' => 'digital-art',
'description' => 'Digital art uploads',
'order' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
$categoryId = DB::table('categories')->insertGetId([
'content_type_id' => $contentTypeId,
'parent_id' => null,
'name' => 'Anime &amp;amp; Manga',
'slug' => 'anime-manga',
'description' => 'Anime &amp;amp; Manga artwork',
'image' => null,
'is_active' => true,
'sort_order' => 1,
'created_at' => now(),
'updated_at' => now(),
]);
$html = $this->actingAs($admin)->actingAs($admin, 'controlpanel')
->get(route('admin.cp.artworks.categories.edit', $categoryId))
->assertOk()
->getContent();
expect($html)
->toContain('value="Anime &amp; Manga"')
->not->toContain('value="Anime &amp;amp; Manga"')
->toContain('Anime &amp; Manga artwork')
->not->toContain('Anime &amp;amp; Manga artwork');
});