diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 8bdb90f..1e0f8b0 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -228,7 +228,10 @@ Tag pair that returns the next X event dates. ### Download Links -Single Tag returns a url to the event data and add it to your calendar. If there's a "location" field (see config above), it'll get added to the download. +Single Tag returns a url to the event data and add it to your calendar. The following fields will be added to the ICS if they exist: + * `location` (see config above) + * `description` + * `link` Parameters: diff --git a/src/Http/Controllers/IcsController.php b/src/Http/Controllers/IcsController.php index b2e9b3f..19e7230 100644 --- a/src/Http/Controllers/IcsController.php +++ b/src/Http/Controllers/IcsController.php @@ -51,7 +51,8 @@ public function __invoke(Request $request) if ($entry) { return $this->downloadIcs( - EventFactory::createFromEntry($entry)->toICalendarEvents() + EventFactory::createFromEntry($entry)->toICalendarEvents(), + $entry->title ); } } diff --git a/src/Types/Event.php b/src/Types/Event.php index e07161f..cb61c3c 100644 --- a/src/Types/Event.php +++ b/src/Types/Event.php @@ -109,10 +109,18 @@ public function toICalendarEvent(string|CarbonInterface $date): ?ICalendarEvent ->startsAt($immutableDate->setTimeFromTimeString($this->startTime())) ->endsAt($immutableDate->setTimeFromTimeString($this->endTime())); - if ($location = $this->location($this->event)) { + if (!is_null($location = $this->location($this->event))) { $iCalEvent->address($location); } + if (!is_null($description = $this->event->description)) { + $iCalEvent->description($description); + } + + if (!is_null($link = $this->event->link)) { + $iCalEvent->url($link); + } + return $iCalEvent; } diff --git a/src/Types/MultiDayEvent.php b/src/Types/MultiDayEvent.php index 876ee8a..5eaa7e7 100644 --- a/src/Types/MultiDayEvent.php +++ b/src/Types/MultiDayEvent.php @@ -59,10 +59,24 @@ public function toICalendarEvent(string|CarbonInterface $date): ?ICalendarEvent $immutableDate = $this->toCarbonImmutable($date); $day = $this->getDayFromDate($immutableDate); - return ICalendarEvent::create($this->event->title) + $iCalEvent = ICalendarEvent::create($this->event->title) ->uniqueIdentifier($this->event->id()) ->startsAt($immutableDate->setTimeFromTimeString($day->start())) ->endsAt($immutableDate->setTimeFromTimeString($day->end())); + + if (! is_null($location = $this->location($this->event))) { + $iCalEvent->address($location); + } + + if (! is_null($description = $this->event->description)) { + $iCalEvent->description($description); + } + + if (! is_null($link = $this->event->link)) { + $iCalEvent->url($link); + } + + return $iCalEvent; } /** @@ -87,7 +101,7 @@ protected function rule(bool $collapseDays = false): RRuleInterface } return tap( - new RSet(), + new RSet, fn (RSet $rset) => $this->days->each(fn (Day $day) => $rset->addRRule([ 'count' => 1, 'dtstart' => $day->end()->subSecond(), diff --git a/src/Types/RecurringEvent.php b/src/Types/RecurringEvent.php index 6af7fe8..a59482a 100644 --- a/src/Types/RecurringEvent.php +++ b/src/Types/RecurringEvent.php @@ -27,15 +27,25 @@ public function interval(): int */ public function toICalendarEvents(): array { - $timezone = $this->timezone['timezone']; - - return [ - ICalendarEvent::create($this->event->title) - ->uniqueIdentifier($this->event->id()) - ->startsAt($this->start()) - ->endsAt($this->end()) - ->rrule($this->spatieRule()), - ]; + $iCalEvent = ICalendarEvent::create($this->event->title) + ->uniqueIdentifier($this->event->id()) + ->startsAt($this->start()) + ->endsAt($this->end()) + ->rrule($this->spatieRule()); + + if (! is_null($location = $this->location($this->event))) { + $iCalEvent->address($location); + } + + if (! is_null($description = $this->event->description)) { + $iCalEvent->description($description); + } + + if (! is_null($link = $this->event->link)) { + $iCalEvent->url($link); + } + + return [$iCalEvent]; } protected function rule(): RRuleInterface diff --git a/tests/Feature/IcsControllerTest.php b/tests/Feature/IcsControllerTest.php index 8aa8aa4..3e60eef 100755 --- a/tests/Feature/IcsControllerTest.php +++ b/tests/Feature/IcsControllerTest.php @@ -23,6 +23,8 @@ protected function setUp(): void 'start_time' => '11:00', 'end_time' => '12:00', 'location' => 'The Location', + 'description' => 'The description', + 'link' => 'https://transformstudios.com' ])->save(); } @@ -38,6 +40,8 @@ public function can_create_single_day_event_ics_file() $this->assertStringContainsString('DTSTART:'.now()->setTimeFromTimeString('11:00')->format('Ymd\THis'), $response->streamedContent()); $this->assertStringContainsString('LOCATION:The Location', $response->streamedContent()); + $this->assertStringContainsString('DESCRIPTION:The description', $response->streamedContent()); + $this->assertStringContainsString('URL:https://transformstudios.com', $response->streamedContent()); } #[Test] @@ -55,6 +59,9 @@ public function can_create_single_day_recurring_event_ics_file() 'start_time' => '11:00', 'end_time' => '12:00', 'recurrence' => 'weekly', + 'location' => 'The Location', + 'description' => 'The description', + 'link' => 'https://transformstudios.com' ])->save(); $response = $this->get(route('statamic.events.ics.show', [ @@ -63,6 +70,9 @@ public function can_create_single_day_recurring_event_ics_file() ]))->assertDownload('recurring-event.ics'); $this->assertStringContainsString('DTSTART:'.now()->setTimeFromTimeString('11:00')->format('Ymd\THis'), $response->streamedContent()); + $this->assertStringContainsString('LOCATION:The Location', $response->streamedContent()); + $this->assertStringContainsString('DESCRIPTION:The description', $response->streamedContent()); + $this->assertStringContainsString('URL:https://transformstudios.com', $response->streamedContent()); $this->get(route('statamic.events.ics.show', [ 'date' => now()->addDay()->toDateString(), @@ -70,18 +80,85 @@ public function can_create_single_day_recurring_event_ics_file() ]))->assertStatus(404); } + #[Test] + public function can_create_ics_with_single_date_recurrence() + { + Carbon::setTestNow(now()->addDay()->setTimeFromTimeString('10:00')); + + Entry::make() + ->collection('events') + ->slug('recurring-event') + ->id('the-recurring-id') + ->data([ + 'title' => 'Recurring Event', + 'start_date' => Carbon::now()->toDateString(), + 'start_time' => '11:00', + 'end_time' => '12:00', + 'recurrence' => 'weekly', + 'location' => 'The Location', + 'description' => 'The description', + 'link' => 'https://transformstudios.com' + ])->save(); + + $response = $this->get(route('statamic.events.ics.show', [ + 'date' => now()->toDateString(), + 'event' => 'the-recurring-id', + ]))->assertDownload('recurring-event.ics'); + + + $this->assertStringContainsString('DTSTART:'.now()->setTimeFromTimeString('11:00')->format('Ymd\THis'), $response->streamedContent()); + $this->assertStringContainsString('LOCATION:The Location', $response->streamedContent()); + $this->assertStringContainsString('DESCRIPTION:The description', $response->streamedContent()); + $this->assertStringContainsString('URL:https://transformstudios.com', $response->streamedContent()); + + } + + #[Test] + public function can_create_ics_with_recurrence() + { + Carbon::setTestNow(now()->addDay()->setTimeFromTimeString('10:00')); + + Entry::make() + ->collection('events') + ->slug('recurring-event') + ->id('the-recurring-id') + ->data([ + 'title' => 'Recurring Event', + 'start_date' => Carbon::now()->toDateString(), + 'start_time' => '11:00', + 'end_time' => '12:00', + 'recurrence' => 'weekly', + 'location' => 'The Location', + 'description' => 'The description', + 'link' => 'https://transformstudios.com' + ])->save(); + + $response = $this->get(route('statamic.events.ics.show', [ + 'event' => 'the-recurring-id', + ]))->assertDownload('recurring-event.ics'); + + $this->assertStringContainsString('DTSTART:'.now()->setTimeFromTimeString('11:00')->format('Ymd\THis'), $response->streamedContent()); + $this->assertStringContainsString('LOCATION:The Location', $response->streamedContent()); + $this->assertStringContainsString('DESCRIPTION:The description', $response->streamedContent()); + $this->assertStringContainsString('URL:https://transformstudios.com', $response->streamedContent()); + + } + #[Test] public function can_create_single_day_multiday_event_ics_file() { Carbon::setTestNow(now()); - $entry = Entry::make() + Entry::make() ->slug('multi-day-event') ->collection('events') ->id('the-multi-day-event') ->data([ 'title' => 'Multi-day Event', 'multi_day' => true, + 'location' => 'The Location', + 'description' => 'The description', + 'link' => 'https://transformstudios.com', 'days' => [ [ 'date' => now()->toDateString(), @@ -112,6 +189,10 @@ public function can_create_single_day_multiday_event_ics_file() ]))->assertDownload('multi-day-event.ics'); $this->assertStringContainsString('DTSTART:'.now()->addDay()->setTimeFromTimeString('11:00')->format('Ymd\THis'), $response->streamedContent()); + $this->assertStringContainsString('LOCATION:The Location', $response->streamedContent()); + $this->assertStringContainsString('DESCRIPTION:The description', $response->streamedContent()); + $this->assertStringContainsString('URL:https://transformstudios.com', $response->streamedContent()); + } #[Test]