177 lines
9.9 KiB
PHP
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.');
|
|
}
|
|
} |