Deploy Ladill Meet / deploy (push) Failing after 7s
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>
121 lines
3.5 KiB
PHP
121 lines
3.5 KiB
PHP
<?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);
|
|
}
|
|
}
|