> $invites */ public function inviteToRoom(Room $room, array $invites, User $host): void { $normalized = collect($invites)->map(function ($invite) { $email = trim((string) ($invite['email'] ?? '')); if ($email === '') { return null; } $user = User::where('email', $email)->first(); return [ 'email' => $email, 'name' => $invite['name'] ?? $invite['display_name'] ?? $user?->name, 'role' => $invite['role'] ?? 'participant', 'user_ref' => $invite['user_ref'] ?? $user?->ownerRef(), ]; })->filter()->unique('email')->values()->all(); $this->notifications->sendInvitations($room, $normalized, $host); } public function resend(Invitation $invitation, User $host): Invitation { $this->notifications->sendInvitationEmail($invitation->room, $invitation, $host); $invitation->update(['sent_at' => now()]); return $invitation->fresh(); } public function respond(Invitation $invitation, string $status, ?string $token = null): Invitation { abort_unless(in_array($status, ['accepted', 'declined'], true), 422); if ($token !== null) { abort_unless(hash_equals((string) $invitation->rsvp_token, $token), 403); } $invitation->update([ 'status' => $status, 'responded_at' => now(), ]); return $invitation->fresh(); } public function markAcceptedOnJoin(Room $room, ?User $user, ?string $email): void { $query = $room->invitations()->where('status', 'pending'); if ($user) { $query->where(function ($q) use ($user, $email) { $q->where('user_ref', $user->ownerRef()); if ($email) { $q->orWhere('email', $email); } }); } elseif ($email) { $query->where('email', $email); } else { return; } $query->update(['status' => 'accepted', 'responded_at' => now()]); } /** * @return array> */ public function parseCsv(string $content): array { $lines = preg_split('/\r\n|\r|\n/', trim($content)) ?: []; $invites = []; foreach ($lines as $index => $line) { $line = trim($line); if ($line === '' || ($index === 0 && str_contains(strtolower($line), 'email'))) { continue; } $parts = str_getcsv($line); $email = trim((string) ($parts[0] ?? '')); if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) { continue; } $invites[] = [ 'email' => $email, 'name' => trim((string) ($parts[1] ?? '')) ?: null, 'role' => trim((string) ($parts[2] ?? '')) ?: 'participant', ]; } return $invites; } public function bulkFromCsv(Room $room, string $csvContent, User $host): int { $invites = $this->parseCsv($csvContent); $this->inviteToRoom($room, $invites, $host); return count($invites); } }