Save workspace changes

This commit is contained in:
2026-04-18 17:02:56 +02:00
parent f02ea9a711
commit 87d60af5a9
4220 changed files with 1388603 additions and 1554 deletions

View File

@@ -0,0 +1,235 @@
<?php
declare(strict_types=1);
namespace App\Http\Controllers\Studio;
use App\Http\Controllers\Controller;
use App\Http\Requests\Groups\StoreGroupRequest;
use App\Http\Requests\Groups\UpdateGroupRequest;
use App\Models\Group;
use App\Services\GroupMembershipService;
use App\Services\GroupService;
use App\Services\GroupArtworkReviewService;
use App\Services\GroupJoinRequestService;
use App\Services\GroupReputationService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class GroupStudioController extends Controller
{
public function __construct(
private readonly GroupService $groups,
private readonly GroupMembershipService $memberships,
private readonly GroupJoinRequestService $joinRequests,
private readonly GroupArtworkReviewService $artworkReviews,
private readonly GroupReputationService $reputation,
) {
}
public function index(Request $request): Response
{
$user = $request->user();
$groups = Group::query()
->with(['owner.profile', 'members'])
->where(function ($query) use ($user): void {
$query->where('owner_user_id', $user->id)
->orWhereHas('members', function ($memberQuery) use ($user): void {
$memberQuery->where('user_id', $user->id)
->where('status', Group::STATUS_ACTIVE);
});
})
->orderBy('name')
->get()
->map(fn (Group $group): array => $this->groups->mapGroupCard($group, $user))
->values()
->all();
return Inertia::render('Studio/StudioGroupsIndex', [
'title' => 'Groups',
'description' => 'Create collective publishing identities, manage memberships, and switch into shared artwork and collection workflows.',
'groups' => $groups,
'pendingInvites' => $this->memberships->pendingInvitationsForUser($user),
'endpoints' => [
'create' => route('studio.groups.create'),
],
]);
}
public function create(): Response
{
$this->authorize('create', Group::class);
return Inertia::render('Studio/StudioGroupCreate', [
'title' => 'Create Group',
'description' => 'Set up a shared publishing identity for collaborative uploads and collections.',
'visibilityOptions' => [
['value' => Group::VISIBILITY_PUBLIC, 'label' => 'Public'],
['value' => Group::VISIBILITY_UNLISTED, 'label' => 'Unlisted'],
['value' => Group::VISIBILITY_PRIVATE, 'label' => 'Private'],
],
'membershipPolicyOptions' => [
['value' => Group::MEMBERSHIP_INVITE_ONLY, 'label' => 'Invite only'],
],
'endpoints' => [
'store' => route('studio.groups.store'),
],
]);
}
public function store(StoreGroupRequest $request): RedirectResponse
{
$this->authorize('create', Group::class);
$group = $this->groups->createGroup($request->user(), $request->validated());
return redirect()->route('studio.groups.show', ['group' => $group]);
}
public function show(Request $request, Group $group): Response
{
$this->authorize('viewStudio', $group);
$viewer = $request->user();
return Inertia::render('Studio/StudioGroupDashboard', [
'title' => $group->name,
'description' => $group->headline ?: 'Shared publishing overview for this group.',
'studioGroup' => $this->groups->mapGroupDetail($group, $viewer),
'dashboard' => $this->groups->studioDashboardSummary($group),
'draftsPendingAction' => $this->groups->studioArtworkPreviewItems($group, 'drafts', 4),
'recentArtworks' => $this->groups->studioArtworkPreviewItems($group, 'published', 6),
'recentCollections' => $this->groups->studioCollectionPreviewItems($group, 4),
'members' => $this->memberships->mapMembers($group, $viewer),
'recentPosts' => $this->groups->recentPostCards($group, 3),
'recentProjects' => $this->groups->recentProjectCards($group, $viewer, 3),
'recentReleases' => $this->groups->recentReleaseCards($group, $viewer, 3),
'recentChallenges' => $this->groups->recentChallengeCards($group, $viewer, 3),
'recentEvents' => $this->groups->recentEventCards($group, $viewer, 3),
'recentActivity' => $this->groups->studioActivityFeed($group, $viewer, 8),
'recruitment' => $this->groups->recruitmentPayload($group),
'reputationSummary' => $this->reputation->summary($group),
'trustSignals' => $this->reputation->trustSignals($group),
'pendingJoinRequests' => $group->canReviewJoinRequests($viewer)
? $this->joinRequests->mapRequests($group, $viewer, ['bucket' => 'pending', 'per_page' => 4])['items']
: [],
'reviewQueuePreview' => $this->artworkReviews->listing($group, $viewer, ['bucket' => 'submitted', 'per_page' => 4])['items'],
'recentHistory' => $this->groups->recentHistory($group, 6),
]);
}
public function artworks(Request $request, Group $group): Response
{
$this->authorize('viewStudio', $group);
return Inertia::render('Studio/StudioGroupArtworks', [
'title' => $group->name . ' Artworks',
'description' => 'Browse every artwork published through this shared identity.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'listing' => $this->groups->studioArtworkListing($group, $request->only(['bucket', 'q', 'page', 'per_page'])),
'uploadUrl' => route('upload', ['group' => $group->slug]),
]);
}
public function collections(Request $request, Group $group): Response
{
$this->authorize('viewStudio', $group);
return Inertia::render('Studio/StudioGroupCollections', [
'title' => $group->name . ' Collections',
'description' => 'Manage collections published under this group identity.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'listing' => $this->groups->studioCollectionListing($group, $request->only(['bucket', 'q', 'page', 'per_page'])),
'createUrl' => route('settings.collections.create', ['group' => $group->slug]),
]);
}
public function members(Request $request, Group $group): Response
{
$this->authorize('viewStudio', $group);
$viewer = $request->user();
$canManageMembers = $group->canManageMembers($viewer);
return Inertia::render('Studio/StudioGroupMembers', [
'title' => $group->name . ' Members',
'description' => 'Invite, remove, and promote the people who can publish and curate under this group.',
'studioGroup' => $this->groups->mapGroupDetail($group, $viewer),
'members' => $this->memberships->mapMembers($group, $viewer),
'canManageMembers' => $canManageMembers,
'permissionOverrideOptions' => array_map(static fn (string $permission): array => [
'value' => $permission,
'label' => str_replace('_', ' ', $permission),
], Group::allowedPermissionOverrides()),
'endpoints' => $canManageMembers ? [
'invite' => route('studio.groups.members.store', ['group' => $group]),
'invitations' => route('studio.groups.invitations', ['group' => $group]),
'updatePattern' => route('studio.groups.members.update', ['group' => $group, 'member' => '__MEMBER__']),
'permissionsPattern' => route('studio.groups.members.permissions.update', ['group' => $group, 'member' => '__MEMBER__']),
'transferPattern' => route('studio.groups.members.transfer', ['group' => $group, 'member' => '__MEMBER__']),
'deletePattern' => route('studio.groups.members.destroy', ['group' => $group, 'member' => '__MEMBER__']),
] : null,
]);
}
public function invitations(Request $request, Group $group): Response
{
$this->authorize('manageMembers', $group);
return Inertia::render('Studio/StudioGroupInvitations', [
'title' => $group->name . ' Invitations',
'description' => 'Manage outstanding invites, resend collaboration roles, and review recent invite history for this group.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'members' => $this->memberships->mapMembers($group, $request->user()),
'invitations' => $this->memberships->mapInvitations($group, $request->user()),
'endpoints' => [
'invite' => route('studio.groups.members.store', ['group' => $group]),
'deletePattern' => route('studio.groups.invitations.destroy', ['group' => $group, 'invitation' => '__INVITATION__']),
],
]);
}
public function settings(Request $request, Group $group): Response
{
$this->authorize('update', $group);
return Inertia::render('Studio/StudioGroupSettings', [
'title' => $group->name . ' Settings',
'description' => 'Update the public presentation and collaboration defaults for this group.',
'studioGroup' => $this->groups->mapGroupDetail($group, $request->user()),
'featuredArtworkOptions' => $this->groups->studioFeaturedArtworkOptions($group),
'visibilityOptions' => [
['value' => Group::VISIBILITY_PUBLIC, 'label' => 'Public'],
['value' => Group::VISIBILITY_UNLISTED, 'label' => 'Unlisted'],
['value' => Group::VISIBILITY_PRIVATE, 'label' => 'Private'],
],
'membershipPolicyOptions' => [
['value' => Group::MEMBERSHIP_INVITE_ONLY, 'label' => 'Invite only'],
],
'endpoints' => [
'update' => route('studio.groups.update', ['group' => $group]),
'archive' => route('studio.groups.archive', ['group' => $group]),
],
]);
}
public function update(UpdateGroupRequest $request, Group $group): RedirectResponse
{
$this->authorize('update', $group);
$group = $this->groups->updateGroup($group, $request->validated(), $request->user());
return redirect()->route('studio.groups.settings', ['group' => $group]);
}
public function archive(Request $request, Group $group): RedirectResponse
{
$this->authorize('archive', $group);
$group = $this->groups->archiveGroup($group, $request->user());
return redirect()->route('studio.groups.settings', ['group' => $group]);
}
}