kithkin/app/Http/Controllers/IcsController.php

68 lines
2.2 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\CalendarInstance;
use Illuminate\Support\Facades\Response;
use Carbon\Carbon;
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
{
$output = [];
$output[] = 'BEGIN:VCALENDAR';
$output[] = 'VERSION:2.0';
$output[] = 'PRODID:-//Kithkin Calendar//EN';
$output[] = 'CALSCALE:GREGORIAN';
$output[] = 'METHOD:PUBLISH';
foreach ($events as $event) {
$meta = $event->meta;
if (!$meta || !$meta->start_at || !$meta->end_at) {
continue;
}
$start = Carbon::parse($meta->start_at)->timezone($tz)->format('Ymd\THis');
$end = Carbon::parse($meta->end_at)->timezone($tz)->format('Ymd\THis');
$output[] = 'BEGIN:VEVENT';
$output[] = 'UID:' . $event->uid;
$output[] = 'SUMMARY:' . $this->escape($meta->title ?? '(Untitled)');
$output[] = 'DESCRIPTION:' . $this->escape($meta->description ?? '');
$output[] = 'DTSTART;TZID=' . $tz . ':' . $start;
$output[] = 'DTEND;TZID=' . $tz . ':' . $end;
$output[] = 'DTSTAMP:' . Carbon::parse($event->lastmodified)->format('Ymd\THis\Z');
if ($meta->location) {
$output[] = 'LOCATION:' . $this->escape($meta->location);
}
$output[] = 'END:VEVENT';
}
$output[] = 'END:VCALENDAR';
return implode("\r\n", $output);
}
protected function escape(?string $text): string
{
return str_replace(['\\', ';', ',', "\n"], ['\\\\', '\;', '\,', '\n'], $text ?? '');
}
}