Sync Ladill Events to the Mail utility calendar.
Events upsert calendar entries by stable external_ref keys, prefer the owner's linked mailbox, and Meet skips mail sync for events-sourced rooms so linked virtual sessions appear only once on the calendar. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\QrCode;
|
||||
use App\Models\User;
|
||||
use App\Services\Events\EventMailCalendarSyncService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EventMailCalendarSyncTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config([
|
||||
'mail_calendar.api_url' => 'https://mail.ladill.com/api/service/v1',
|
||||
'mail_calendar.api_key' => 'test-events-mail-key',
|
||||
'identity.api_url' => 'https://ladill.com/api',
|
||||
'identity.api_key' => 'test-identity-key',
|
||||
]);
|
||||
|
||||
Http::fake([
|
||||
'https://ladill.com/api/identity/mailbox-link*' => Http::response(['data' => []]),
|
||||
'https://mail.ladill.com/*' => Http::response(['data' => ['id' => 55]], 201),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_in_person_event_syncs_to_mail_calendar(): void
|
||||
{
|
||||
$owner = User::factory()->create(['public_id' => 'usr-cal-1', 'email' => 'host@example.com']);
|
||||
$event = $this->makeEvent($owner, [
|
||||
'format' => 'in_person',
|
||||
'name' => 'Town hall',
|
||||
'starts_at' => now()->addWeek()->toDateString(),
|
||||
'ends_at' => now()->addWeek()->addHours(3)->toDateString(),
|
||||
]);
|
||||
|
||||
app(EventMailCalendarSyncService::class)->sync($event, $owner);
|
||||
|
||||
Http::assertSent(function ($request) use ($event) {
|
||||
return str_contains($request->url(), '/calendar/events')
|
||||
&& $request['mailbox_email'] === 'host@example.com'
|
||||
&& $request['external_ref'] === 'events:'.$event->id
|
||||
&& $request['title'] === 'Town hall';
|
||||
});
|
||||
|
||||
$this->assertSame(
|
||||
['events:'.$event->id => 55],
|
||||
data_get($event->fresh()->payload, 'calendar_sync.items'),
|
||||
);
|
||||
}
|
||||
|
||||
public function test_virtual_session_syncs_one_entry_with_meet_join_url(): void
|
||||
{
|
||||
$owner = User::factory()->create(['public_id' => 'usr-cal-3', 'email' => 'host@example.com']);
|
||||
$event = $this->makeEvent($owner, [
|
||||
'format' => 'virtual',
|
||||
'name' => 'Product launch',
|
||||
'starts_at' => now()->addWeek()->toDateString(),
|
||||
'virtual_sessions' => [[
|
||||
'id' => 'vs-main',
|
||||
'title' => 'Main stage',
|
||||
'scheduled_at' => now()->addWeek()->toIso8601String(),
|
||||
'duration_minutes' => 90,
|
||||
'join_url' => 'https://meet.ladill.com/join/demo',
|
||||
]],
|
||||
]);
|
||||
|
||||
app(EventMailCalendarSyncService::class)->sync($event, $owner);
|
||||
|
||||
Http::assertSent(function ($request) use ($event) {
|
||||
return str_contains($request->url(), '/calendar/events')
|
||||
&& $request['external_ref'] === 'events:'.$event->id.':session:vs-main'
|
||||
&& $request['join_url'] === 'https://meet.ladill.com/join/demo';
|
||||
});
|
||||
|
||||
$this->assertSame(1, collect(Http::recorded())->filter(
|
||||
fn (array $pair) => str_contains($pair[0]->url(), '/calendar/events'),
|
||||
)->count());
|
||||
}
|
||||
|
||||
public function test_uses_linked_mailbox_when_available(): void
|
||||
{
|
||||
Http::fake([
|
||||
'https://mail.ladill.com/*' => Http::response(['data' => ['id' => 77]], 201),
|
||||
]);
|
||||
|
||||
$this->mock(\App\Services\Identity\IdentityClient::class, function ($mock) {
|
||||
$mock->shouldReceive('mailboxLinkStatus')
|
||||
->once()
|
||||
->andReturn(['linked_mailbox' => 'owner@customdomain.com']);
|
||||
});
|
||||
|
||||
$owner = User::factory()->create(['public_id' => 'usr-cal-2', 'email' => 'sso@ladill.com']);
|
||||
$event = $this->makeEvent($owner, [
|
||||
'format' => 'in_person',
|
||||
'name' => 'Gala',
|
||||
'starts_at' => now()->addWeek()->toDateString(),
|
||||
]);
|
||||
|
||||
app(EventMailCalendarSyncService::class)->sync($event, $owner);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
return str_contains($request->url(), '/calendar/events')
|
||||
&& ($request['mailbox_email'] ?? '') === 'owner@customdomain.com';
|
||||
});
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $content */
|
||||
private function makeEvent(User $owner, array $content): QrCode
|
||||
{
|
||||
return QrCode::create([
|
||||
'user_id' => $owner->id,
|
||||
'short_code' => 'evt-cal-'.uniqid(),
|
||||
'type' => QrCode::TYPE_EVENT,
|
||||
'label' => (string) ($content['name'] ?? 'Event'),
|
||||
'payload' => ['content' => $content, 'style' => []],
|
||||
'is_active' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user