Files
SkinbaseNova/.deploy/artwork-evolution-release/app/Http/Controllers/Studio/GroupReleaseStudioController.php
2026-04-18 17:02:56 +02:00

177 lines
9.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Studio;
use App\Http\Controllers\Controller;
use App\Http\Requests\Groups\AttachArtworkToGroupReleaseRequest;
use App\Http\Requests\Groups\AttachContributorToGroupReleaseRequest;
use App\Http\Requests\Groups\StoreGroupMilestoneRequest;
use App\Http\Requests\Groups\StoreGroupReleaseRequest;
use App\Http\Requests\Groups\UpdateGroupMilestoneRequest;
use App\Http\Requests\Groups\UpdateGroupReleaseRequest;
use App\Http\Requests\Groups\UpdateGroupReleaseStageRequest;
use App\Models\Artwork;
use App\Models\Group;
use App\Models\GroupRelease;
use App\Models\GroupReleaseMilestone;
use App\Models\User;
use App\Services\GroupReleaseService;
use App\Services\GroupService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class GroupReleaseStudioController extends Controller
{
public function __construct(
private readonly GroupService $groups,
private readonly GroupReleaseService $releases,
) {
}
public function index(Request $request, Group $group): Response
{
$this->authorize('manageReleases', $group);
return Inertia::render('Studio/StudioGroupReleases', [
'title' => $group->name . ' Releases',
'description' => 'Manage release pipelines, contributors, and publication stages for major group drops.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'listing' => $this->releases->studioListing($group, $request->only(['bucket', 'page', 'per_page'])),
'createUrl' => route('studio.groups.releases.create', ['group' => $group]),
]);
}
public function create(Request $request, Group $group): Response
{
$this->authorize('manageReleases', $group);
return Inertia::render('Studio/StudioGroupReleaseEditor', [
'title' => 'Create release',
'description' => 'Build a release page and move it from concept through publishing.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'release' => null,
'statusOptions' => collect((array) config('groups.releases.statuses', []))->map(fn (string $value): array => ['value' => $value, 'label' => str_replace('_', ' ', ucfirst($value))])->values()->all(),
'stageOptions' => collect((array) config('groups.releases.stages', []))->map(fn (string $value): array => ['value' => $value, 'label' => ucfirst($value)])->values()->all(),
'visibilityOptions' => collect((array) config('groups.releases.visibility_options', []))->map(fn (string $value): array => ['value' => $value, 'label' => ucfirst($value)])->values()->all(),
'memberOptions' => $this->releases->memberOptions($group->loadMissing('owner.profile')),
'projectOptions' => $group->projects()->orderBy('title')->get(['id', 'title'])->map(fn ($project): array => ['id' => (int) $project->id, 'title' => $project->title])->values()->all(),
'collectionOptions' => $group->collections()->orderBy('title')->get(['id', 'title'])->map(fn ($collection): array => ['id' => (int) $collection->id, 'title' => $collection->title])->values()->all(),
'artworkOptions' => $group->artworks()->whereNull('deleted_at')->latest('updated_at')->limit(30)->get(['id', 'title'])->map(fn ($artwork): array => ['id' => (int) $artwork->id, 'title' => $artwork->title])->values()->all(),
'storeUrl' => route('studio.groups.releases.store', ['group' => $group]),
]);
}
public function store(StoreGroupReleaseRequest $request, Group $group): RedirectResponse
{
$this->authorize('manageReleases', $group);
$release = $this->releases->create($group, $request->user(), $request->validated());
return redirect()->route('studio.groups.releases.show', ['group' => $group, 'release' => $release])
->with('success', 'Release created.');
}
public function show(Request $request, Group $group, GroupRelease $release): Response
{
$this->authorize('manageReleases', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
return Inertia::render('Studio/StudioGroupReleaseEditor', [
'title' => 'Edit release',
'description' => 'Update the release story, stage, contributors, and publish plan.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'release' => $this->releases->detailPayload($release, $request->user()),
'statusOptions' => collect((array) config('groups.releases.statuses', []))->map(fn (string $value): array => ['value' => $value, 'label' => str_replace('_', ' ', ucfirst($value))])->values()->all(),
'stageOptions' => collect((array) config('groups.releases.stages', []))->map(fn (string $value): array => ['value' => $value, 'label' => ucfirst($value)])->values()->all(),
'visibilityOptions' => collect((array) config('groups.releases.visibility_options', []))->map(fn (string $value): array => ['value' => $value, 'label' => ucfirst($value)])->values()->all(),
'memberOptions' => $this->releases->memberOptions($group->loadMissing('owner.profile')),
'projectOptions' => $group->projects()->orderBy('title')->get(['id', 'title'])->map(fn ($project): array => ['id' => (int) $project->id, 'title' => $project->title])->values()->all(),
'collectionOptions' => $group->collections()->orderBy('title')->get(['id', 'title'])->map(fn ($collection): array => ['id' => (int) $collection->id, 'title' => $collection->title])->values()->all(),
'artworkOptions' => $group->artworks()->whereNull('deleted_at')->latest('updated_at')->limit(30)->get(['id', 'title'])->map(fn ($artwork): array => ['id' => (int) $artwork->id, 'title' => $artwork->title])->values()->all(),
'updateUrl' => route('studio.groups.releases.update', ['group' => $group, 'release' => $release]),
'stageUrl' => route('studio.groups.releases.stage', ['group' => $group, 'release' => $release]),
'publishUrl' => route('studio.groups.releases.publish', ['group' => $group, 'release' => $release]),
'attachArtworkUrl' => route('studio.groups.releases.attach-artwork', ['group' => $group, 'release' => $release]),
'attachContributorUrl' => route('studio.groups.releases.attach-contributor', ['group' => $group, 'release' => $release]),
'storeMilestoneUrl' => route('studio.groups.releases.milestones.store', ['group' => $group, 'release' => $release]),
'updateMilestonePattern' => route('studio.groups.releases.milestones.update', ['group' => $group, 'release' => $release, 'milestone' => '__MILESTONE__']),
]);
}
public function update(UpdateGroupReleaseRequest $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('manageReleases', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$this->releases->update($release, $request->user(), $request->validated());
return back()->with('success', 'Release updated.');
}
public function stage(UpdateGroupReleaseStageRequest $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('moveReleaseStage', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$this->releases->updateStage($release, $request->user(), (string) $request->validated('current_stage'));
return back()->with('success', 'Release stage updated.');
}
public function publish(Request $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('publishReleases', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$this->releases->publish($release, $request->user());
return back()->with('success', 'Release published.');
}
public function attachArtwork(AttachArtworkToGroupReleaseRequest $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('manageReleases', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$artwork = Artwork::query()->findOrFail((int) $request->validated('artwork_id'));
$this->releases->attachArtwork($release, $artwork, $request->user());
return back()->with('success', 'Artwork attached to release.');
}
public function attachContributor(AttachContributorToGroupReleaseRequest $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('manageReleases', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$contributor = User::query()->findOrFail((int) $request->validated('user_id'));
$this->releases->attachContributor($release, $contributor, $request->user(), $request->validated('role_label'));
return back()->with('success', 'Contributor attached to release.');
}
public function storeMilestone(StoreGroupMilestoneRequest $request, Group $group, GroupRelease $release): RedirectResponse
{
$this->authorize('manageMilestones', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
$this->releases->createMilestone($release, $request->user(), $request->validated());
return back()->with('success', 'Release milestone created.');
}
public function updateMilestone(UpdateGroupMilestoneRequest $request, Group $group, GroupRelease $release, GroupReleaseMilestone $milestone): RedirectResponse
{
$this->authorize('manageMilestones', $group);
abort_unless((int) $release->group_id === (int) $group->id, 404);
abort_unless((int) $milestone->group_release_id === (int) $release->id, 404);
$this->releases->updateMilestone($milestone, $request->user(), $request->validated());
return back()->with('success', 'Release milestone updated.');
}
}