trypost/app/Http/Controllers/Auth/AcceptInviteController.php
Paulo Castellano 2da15df96c feat: introduce Account entity as billing owner and refactor architecture
- Create Account model as Cashier Billable entity (stripe, plan, subscription)
- Account owns workspaces and has an owner_id (User)
- User belongs to one Account via account_id
- Workspace belongs to Account via account_id, no longer has billing fields
- Remove Brand model entirely (workspaces serve as grouping)
- Rename brand_limit to workspace_limit in plans
- Workspace roles simplified: admin/member/viewer (owner via Account)
- Invites now belong to Account with workspaces JSON array
- Pennant features scope changed from Workspace to Account
- EnsureSubscribed middleware checks Account subscription
- All controllers updated: BillingController, OnboardingController,
  WorkspaceInviteController, SocialController, StripeEventListener
- Frontend: extract GoogleAuthButton component, create WorkspaceRole
  enum for type-safe role checks, fix all views for new architecture
- All 1101 tests passing
2026-04-14 22:22:04 -03:00

114 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Http\Controllers\Auth;
use App\Enums\UserWorkspace\Role;
use App\Http\Controllers\Controller;
use App\Models\Invite;
use App\Models\Workspace;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class AcceptInviteController extends Controller
{
/**
* Display the invite view.
*/
public function show(Invite $invite): Response
{
$invite->load('account');
return Inertia::render('auth/AcceptInvite', [
'invite' => [
'id' => $invite->id,
'email' => $invite->email,
'account' => [
'id' => $invite->account->id,
'name' => $invite->account->name,
],
'workspaces' => $invite->workspaces,
],
]);
}
/**
* Accept the invite.
*/
public function accept(Request $request, Invite $invite): RedirectResponse
{
$user = $request->user();
// Verify the invite is for this user
if ($invite->email !== $user->email) {
session()->flash('flash.banner', __('settings.members.flash.wrong_email'));
session()->flash('flash.bannerStyle', 'danger');
return redirect()->route('app.calendar');
}
// Check if already a member of the account
if ($user->account_id === $invite->account_id) {
$invite->update(['accepted_at' => now()]);
session()->flash('flash.banner', __('settings.members.flash.already_member'));
session()->flash('flash.bannerStyle', 'info');
return redirect()->route('app.calendar');
}
// Add user to the account
$user->update(['account_id' => $invite->account_id]);
// Attach user to the invited workspaces
if ($invite->workspaces) {
foreach ($invite->workspaces as $workspaceId) {
$workspace = Workspace::find($workspaceId);
if ($workspace && $workspace->account_id === $invite->account_id) {
$workspace->members()->syncWithoutDetaching([
$user->id => ['role' => Role::Member->value],
]);
// Set first workspace as current
if (! $user->current_workspace_id) {
$user->update(['current_workspace_id' => $workspace->id]);
}
}
}
}
$invite->update(['accepted_at' => now()]);
session()->flash('flash.banner', __('settings.members.flash.invite_accepted'));
session()->flash('flash.bannerStyle', 'success');
return redirect()->route('app.calendar');
}
/**
* Decline the invite.
*/
public function decline(Request $request, Invite $invite): RedirectResponse
{
$user = $request->user();
// Verify the invite is for this user
if ($invite->email !== $user->email) {
session()->flash('flash.banner', __('settings.members.flash.wrong_email'));
session()->flash('flash.bannerStyle', 'danger');
return redirect()->route('app.calendar');
}
$invite->delete();
session()->flash('flash.banner', __('settings.members.flash.invite_declined'));
session()->flash('flash.bannerStyle', 'info');
return redirect()->route('app.calendar');
}
}