68 lines
2.2 KiB
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 ?? '');
|
|
}
|
|
}
|