Phases 0–18: core meetings, webinar, breakouts, team chat, live streaming, town hall, billing, and Ladill Mail calendar wiring. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Meet;
|
||||
|
||||
use App\Models\Invitation;
|
||||
use App\Models\Room;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class InvitationService
|
||||
{
|
||||
public function __construct(
|
||||
protected MeetNotificationService $notifications,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param array<int, array<string, mixed>> $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<int, array<string, mixed>>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user