authorize('update', $dynamic); return Inertia::render('Dynamics/Invite', [ 'dynamic' => $dynamic, ]); } /** * Store a newly created invitation in storage. */ public function store(Request $request, Dynamic $dynamic) { // 1. Authorize - only owners can send invitations! $isOwner = $dynamic->participants() ->where('user_id', $request->user()->id) ->where('role', 'owner') ->exists(); if (! $isOwner) { abort(403, 'Only dynamic owners can invite other users.'); } // 2. Validate $request->validate([ 'email' => ['required', 'email'], 'role' => ['required', 'string', 'in:owner,participant,editor,viewer'], ]); $email = $request->input('email'); $role = $request->input('role'); // Check if user is already a participant of this dynamic $isParticipant = $dynamic->participants()->where('email', $email)->exists(); if ($isParticipant) { return redirect()->back()->withErrors([ 'email' => 'This user is already a participant of this dynamic.', ]); } // Check if there is an active pending invitation for this user $hasPendingInvite = $dynamic->invitations() ->where('email', $email) ->where('expires_at', '>', now()) ->exists(); if ($hasPendingInvite) { return redirect()->back()->withErrors([ 'email' => 'An active invitation is already pending for this email address.', ]); } // 3. Create Invitation $invitation = $dynamic->invitations()->create([ 'email' => $email, 'role' => $role, 'token' => Str::random(40), 'expires_at' => now()->addDays(7), ]); // 4. Send Email Mail::to($email)->send(new DynamicInvitationMail($invitation, $request->user()->name)); return redirect()->back()->with('success', 'Invitation successfully sent!'); } /** * Accept the specified invitation. */ public function accept(Request $request, string $token) { // Must be signed! if (! $request->hasValidSignature()) { abort(401, 'Invalid or expired signature.'); } $invitation = DynamicInvitation::where('token', $token)->firstOrFail(); if ($invitation->isExpired()) { abort(403, 'This invitation has expired.'); } // Ensure the logged in user's email matches the invitation's email! // "Only the user with the specified email address should be able to access the link." if ($request->user()->email !== $invitation->email) { abort(403, 'This invitation was sent to a different email address.'); } DB::transaction(function () use ($request, $invitation) { // Attach user to dynamic as a participant with the specified role $dynamic = $invitation->dynamic; $dynamic->participants()->attach($request->user()->id, ['role' => $invitation->role]); // Log to Dynamic chat activity log! $dynamic->chat->messages()->create([ 'user_id' => null, 'content' => "user()->id}> joined the Dynamic as a ".strtoupper($invitation->role), 'subject_id' => $request->user()->id, 'subject_type' => User::class, ]); // Delete the invitation record $invitation->delete(); }); return redirect()->route('dynamics.show', $invitation->dynamic)->with('success', 'Successfully joined the dynamic!'); } }