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

@@ -9,6 +9,7 @@ use App\Models\Artwork;
use App\Models\Category;
use App\Models\ContentType;
use App\Models\ArtworkVersion;
use App\Services\ArtworkEvolutionService;
use App\Services\Cdn\ArtworkCdnPurgeService;
use App\Services\ArtworkSearchIndexer;
use App\Services\ArtworkAttributionService;
@@ -122,6 +123,7 @@ final class StudioArtworksApiController extends Controller
public function update(Request $request, int $id, ArtworkAttributionService $attribution): JsonResponse
{
$artwork = $request->user()->artworks()->findOrFail($id);
$evolution = app(ArtworkEvolutionService::class);
$validated = $request->validate([
'title' => 'sometimes|string|max:255',
@@ -133,7 +135,7 @@ final class StudioArtworksApiController extends Controller
'timezone' => 'sometimes|nullable|string|max:64',
'category_id' => 'sometimes|nullable|integer|exists:categories,id',
'content_type_id' => 'sometimes|nullable|integer|exists:content_types,id',
'tags' => 'sometimes|array|max:15',
'tags' => 'sometimes|array|max:' . (int) config('tags.max_user_tags', 30),
'tags.*' => 'string|max:64',
'title_source' => 'sometimes|nullable|string|in:manual,ai_generated,ai_applied,mixed',
'description_source' => 'sometimes|nullable|string|in:manual,ai_generated,ai_applied,mixed',
@@ -147,12 +149,18 @@ final class StudioArtworksApiController extends Controller
'contributor_credits.*.user_id' => 'required|integer|min:1',
'contributor_credits.*.credit_role' => 'nullable|string|max:80',
'contributor_credits.*.is_primary' => 'nullable|boolean',
'evolution_target_artwork_id' => 'sometimes|nullable|integer|min:1',
'evolution_relation_type' => 'sometimes|nullable|string|in:remake_of,remaster_of,revision_of,inspired_by,variation_of',
'evolution_note' => 'sometimes|nullable|string|max:1200',
]);
$hasAttributionUpdates = array_key_exists('group', $validated)
|| array_key_exists('primary_author_user_id', $validated)
|| array_key_exists('contributor_user_ids', $validated)
|| array_key_exists('contributor_credits', $validated);
$hasEvolutionUpdates = array_key_exists('evolution_target_artwork_id', $validated)
|| array_key_exists('evolution_relation_type', $validated)
|| array_key_exists('evolution_note', $validated);
$attributionPayload = [
'group' => $validated['group'] ?? $artwork->group?->slug,
@@ -190,7 +198,13 @@ final class StudioArtworksApiController extends Controller
$tags = $validated['tags'] ?? null;
$categoryId = $validated['category_id'] ?? null;
$contentTypeId = $validated['content_type_id'] ?? null;
$evolutionPayload = [
'target_artwork_id' => $validated['evolution_target_artwork_id'] ?? null,
'relation_type' => $validated['evolution_relation_type'] ?? null,
'note' => $validated['evolution_note'] ?? null,
];
unset($validated['tags'], $validated['category_id'], $validated['content_type_id'], $validated['visibility'], $validated['mode'], $validated['publish_at'], $validated['timezone'], $validated['group'], $validated['primary_author_user_id'], $validated['contributor_user_ids'], $validated['contributor_credits']);
unset($validated['evolution_target_artwork_id'], $validated['evolution_relation_type'], $validated['evolution_note']);
$validated['visibility'] = $visibility;
$validated['artwork_timezone'] = $timezone;
@@ -244,6 +258,14 @@ final class StudioArtworksApiController extends Controller
$artwork = $attribution->apply($artwork->fresh(['group.members', 'contributors', 'primaryAuthor.profile']), $request->user(), $attributionPayload);
}
if ($hasEvolutionUpdates) {
try {
$evolution->syncPrimaryRelation($artwork->fresh(['group.members']), $request->user(), $evolutionPayload);
} catch (ValidationException $exception) {
return response()->json(['errors' => $exception->errors()], 422);
}
}
// Reindex in Meilisearch
try {
if ((bool) $artwork->is_public && (bool) $artwork->is_approved && $artwork->published_at) {
@@ -287,6 +309,25 @@ final class StudioArtworksApiController extends Controller
'description_source' => $artwork->description_source ?: 'manual',
'tags_source' => $artwork->tags_source ?: 'manual',
'category_source' => $artwork->category_source ?: 'manual',
'evolution_relation' => $evolution->editorRelation($artwork, $request->user()),
],
]);
}
public function evolutionOptions(Request $request, int $id): JsonResponse
{
$artwork = $request->user()->artworks()->findOrFail($id);
$validated = $request->validate([
'search' => ['nullable', 'string', 'max:120'],
]);
$evolution = app(ArtworkEvolutionService::class);
return response()->json([
'data' => $evolution->manageableSearchOptions($artwork, $request->user(), (string) ($validated['search'] ?? '')),
'meta' => [
'selected' => $evolution->editorRelation($artwork, $request->user()),
],
]);
}