kithkin/app/Http/Controllers/IcsController.php

79 lines
2.6 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\CalendarInstance;
use Illuminate\Support\Facades\Response;
use Carbon\Carbon;
use Sabre\VObject\Component\VCalendar;
use Sabre\VObject\Reader;
class IcsController extends Controller
{
public function download(string $calendarUri)
{
$instance = CalendarInstance::where('uri', $calendarUri)->firstOrFail();
$calendar = $instance->calendar()->with(['events.meta'])->firstOrFail();
$timezone = $instance->timezone ?? 'UTC';
$ical = $this->generateICalendarFeed($calendar->events, $timezone);
return Response::make($ical, 200, [
'Content-Type' => 'text/calendar; charset=utf-8',
'Content-Disposition' => 'inline; filename="' . $calendarUri . '.ics"',
]);
}
protected function generateICalendarFeed($events, string $tz): string
{
$vcalendar = new VCalendar();
$vcalendar->add('VERSION', '2.0');
$vcalendar->add('PRODID', '-//Kithkin Calendar//EN');
$vcalendar->add('CALSCALE', 'GREGORIAN');
$vcalendar->add('METHOD', 'PUBLISH');
foreach ($events as $event) {
$ical = $event->calendardata ?? null;
if ($ical) {
try {
$parsed = Reader::read($ical);
foreach ($parsed->select('VEVENT') as $vevent) {
$vcalendar->add(clone $vevent);
}
continue;
} catch (\Throwable $e) {
// fall through to meta-based output
}
}
$meta = $event->meta;
if (!$meta || !$meta->start_at || !$meta->end_at) {
continue;
}
$start = Carbon::parse($meta->start_at)->timezone($tz);
$end = Carbon::parse($meta->end_at)->timezone($tz);
$vevent = $vcalendar->add('VEVENT', []);
$vevent->add('UID', $event->uid);
$vevent->add('SUMMARY', $meta->title ?? '(Untitled)');
$vevent->add('DESCRIPTION', $meta->description ?? '');
$vevent->add('DTSTART', $start, ['TZID' => $tz]);
$vevent->add('DTEND', $end, ['TZID' => $tz]);
$vevent->add('DTSTAMP', Carbon::parse($event->lastmodified)->utc());
if ($meta->location) {
$vevent->add('LOCATION', $meta->location);
}
}
return $vcalendar->serialize();
}
protected function escape(?string $text): string
{
return str_replace(['\\', ';', ',', "\n"], ['\\\\', '\;', '\,', '\n'], $text ?? '');
}
}