Added ics calendar
This commit is contained in:
parent
0d4a34c4ad
commit
ec166854cb
71
composer.lock
generated
71
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "df89229d36c9d3133b8f00872aefe73d",
|
||||
"content-hash": "3affcf22479997bf7bae2bd6b9c0cf5e",
|
||||
"packages": [
|
||||
{
|
||||
"name": "dflydev/hawk",
|
||||
@ -893,6 +893,75 @@
|
||||
},
|
||||
"time": "2019-03-08T08:55:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/asset",
|
||||
"version": "v7.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/asset.git",
|
||||
"reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/asset/zipball/cb926cd59fefa1f9b4900b3695f0f846797ba5c0",
|
||||
"reference": "cb926cd59fefa1f9b4900b3695f0f846797ba5c0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-foundation": "<6.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/http-client": "^6.4|^7.0",
|
||||
"symfony/http-foundation": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Asset\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/asset/tree/v7.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-25T15:15:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/cache",
|
||||
"version": "v7.2.4",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Service\AbsenceManager;
|
||||
use App\Service\CalendarExportService;
|
||||
use App\Service\CalendarService;
|
||||
use DateTime;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@ -15,6 +16,7 @@ final class CalendarController extends AbstractController
|
||||
public function __construct(
|
||||
private readonly AbsenceManager $absenceManager,
|
||||
private readonly CalendarService $calendarService,
|
||||
private readonly CalendarExportService $calendarExportService,
|
||||
private readonly string $requiredApiKey
|
||||
) {
|
||||
}
|
||||
@ -40,4 +42,28 @@ final class CalendarController extends AbstractController
|
||||
'days' => $days,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/cal', name: 'calendar_ics')]
|
||||
public function exportCalendarIcs(Request $request): Response
|
||||
{
|
||||
if (!$request->query->has('key') || $request->query->get('key') !== $this->requiredApiKey) {
|
||||
return new Response('Kein Zugriff', Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
|
||||
$startDate = (new DateTime())->format('Y-m-d');
|
||||
$endDate = (new DateTime('+180 days'))->format('Y-m-d');
|
||||
|
||||
$absences = $this->absenceManager->getAbsencesForUser('tim.lappe@check24.de', new DateTime('-1 day'));
|
||||
|
||||
$days = $this->calendarService->getAllDays($startDate, $endDate);
|
||||
$days = $this->calendarService->processAbsences($days, $absences);
|
||||
|
||||
$icsContent = $this->calendarExportService->generateIcsContent($days, $absences);
|
||||
|
||||
$response = new Response($icsContent);
|
||||
$response->headers->set('Content-Type', 'text/calendar; charset=utf-8');
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="work_calendar.ics"');
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
107
src/Service/CalendarExportService.php
Normal file
107
src/Service/CalendarExportService.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Model\Absence;
|
||||
use DateTime;
|
||||
use DateTimeInterface;
|
||||
use DateTimeZone;
|
||||
|
||||
final class CalendarExportService
|
||||
{
|
||||
private const DUSSELDORF_ADDRESS = 'CHECK24 \nHeinricht-Heine-Allee 53\n40213 Düsseldorf\nDeutschland';
|
||||
private const KAMEN_ADDRESS = 'Privat \nHeidkamp 21\n59174 Kamen\nDeutschland';
|
||||
private const COMPANY_NAME = 'CHECK24';
|
||||
private const TIMEZONE = 'Europe/Berlin';
|
||||
|
||||
public function generateIcsContent(array $days, array $absences): string
|
||||
{
|
||||
$icsContent = [
|
||||
'BEGIN:VCALENDAR',
|
||||
'VERSION:2.0',
|
||||
'PRODID:-//CHECK24//Work Calendar//EN',
|
||||
'CALSCALE:GREGORIAN',
|
||||
'METHOD:PUBLISH',
|
||||
$this->generateTimezone(),
|
||||
];
|
||||
|
||||
foreach ($days as $day) {
|
||||
if ($this->isWeekend($day) || ($day['isUrlaub'] ?? false)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$eventStart = clone $day['date'];
|
||||
$eventStart->setTime(9, 0, 0);
|
||||
|
||||
$eventEnd = clone $day['date'];
|
||||
$eventEnd->setTime(17, 30, 0);
|
||||
|
||||
$isHomeOffice = $day['isFtk'] ?? false;
|
||||
$location = $isHomeOffice ? self::KAMEN_ADDRESS : self::DUSSELDORF_ADDRESS;
|
||||
|
||||
$name = match ($isHomeOffice) {
|
||||
true => 'CHECK24 🏠',
|
||||
false => 'CHECK24 🏢',
|
||||
};
|
||||
|
||||
$icsContent[] = 'BEGIN:VEVENT';
|
||||
$icsContent[] = 'UID:' . $this->generateUid($eventStart);
|
||||
$icsContent[] = 'DTSTAMP:' . $this->formatDateTime(new DateTime('now', new DateTimeZone(self::TIMEZONE)));
|
||||
$icsContent[] = 'DTSTART;TZID=' . self::TIMEZONE . ':' . $this->formatDateTimeLocal($eventStart);
|
||||
$icsContent[] = 'DTEND;TZID=' . self::TIMEZONE . ':' . $this->formatDateTimeLocal($eventEnd);
|
||||
$icsContent[] = 'SUMMARY:' . $name;
|
||||
$icsContent[] = 'LOCATION:' . $location;
|
||||
$icsContent[] = 'END:VEVENT';
|
||||
}
|
||||
|
||||
$icsContent[] = 'END:VCALENDAR';
|
||||
|
||||
return implode("\r\n", $icsContent);
|
||||
}
|
||||
|
||||
private function isWeekend(array $day): bool
|
||||
{
|
||||
return $day['weekday'] >= 6;
|
||||
}
|
||||
|
||||
private function formatDateTime(DateTimeInterface $dateTime): string
|
||||
{
|
||||
$utcDateTime = clone $dateTime;
|
||||
$utcDateTime->setTimezone(new DateTimeZone('UTC'));
|
||||
return $utcDateTime->format('Ymd\THis\Z');
|
||||
}
|
||||
|
||||
private function formatDateTimeLocal(DateTimeInterface $dateTime): string
|
||||
{
|
||||
return $dateTime->format('Ymd\THis');
|
||||
}
|
||||
|
||||
private function generateUid(DateTimeInterface $dateTime): string
|
||||
{
|
||||
return $dateTime->format('Ymd') . '-' . md5($dateTime->format('Ymd') . '-CHECK24') . '@check24.de';
|
||||
}
|
||||
|
||||
private function generateTimezone(): string
|
||||
{
|
||||
return implode("\r\n", [
|
||||
'BEGIN:VTIMEZONE',
|
||||
'TZID:' . self::TIMEZONE,
|
||||
'X-LIC-LOCATION:' . self::TIMEZONE,
|
||||
'BEGIN:DAYLIGHT',
|
||||
'TZOFFSETFROM:+0100',
|
||||
'TZOFFSETTO:+0200',
|
||||
'TZNAME:CEST',
|
||||
'DTSTART:19700329T020000',
|
||||
'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU',
|
||||
'END:DAYLIGHT',
|
||||
'BEGIN:STANDARD',
|
||||
'TZOFFSETFROM:+0200',
|
||||
'TZOFFSETTO:+0100',
|
||||
'TZNAME:CET',
|
||||
'DTSTART:19701025T030000',
|
||||
'RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU',
|
||||
'END:STANDARD',
|
||||
'END:VTIMEZONE',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user