Improved calendar performance
This commit is contained in:
parent
0fbc7ddd20
commit
603bf0a5a2
@ -1,4 +1,4 @@
|
||||
FROM php:8.2-cli
|
||||
FROM php:8.2-cli as base
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
@ -21,14 +21,15 @@ RUN curl -sS https://get.symfony.com/cli/installer | bash && \
|
||||
# Set working directory
|
||||
WORKDIR /var/www/html
|
||||
|
||||
CMD ["symfony", "serve", "--port=8000", "--no-tls", "--allow-http", "--allow-all-ip"]
|
||||
|
||||
FROM base as production
|
||||
|
||||
# Copy application files
|
||||
COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN composer install --no-interaction --optimize-autoloader
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Command to run Symfony server
|
||||
CMD ["symfony", "serve", "--port=8000", "--no-tls", "--allow-http", "--allow-all-ip"]
|
||||
|
||||
@ -5,8 +5,9 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: production
|
||||
environment:
|
||||
- APP_ENV=dev
|
||||
- APP_ENV=prod
|
||||
- APP_DEBUG=1
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
@ -3,6 +3,11 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
target: base
|
||||
ports:
|
||||
- 8000:8000
|
||||
environment:
|
||||
- APP_ENV=dev
|
||||
- APP_DEBUG=1
|
||||
- APP_DEBUG=1
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\HomeAssistant\HomeAssistantClient;
|
||||
use App\Service\AbsenceManager;
|
||||
use App\Service\CalendarExportService;
|
||||
use App\Service\CalendarService;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
@ -17,6 +19,7 @@ final class CalendarController extends AbstractController
|
||||
private readonly AbsenceManager $absenceManager,
|
||||
private readonly CalendarService $calendarService,
|
||||
private readonly CalendarExportService $calendarExportService,
|
||||
private readonly HomeAssistantClient $homeAssistantClient,
|
||||
private readonly string $requiredApiKey
|
||||
) {
|
||||
}
|
||||
@ -57,12 +60,18 @@ final class CalendarController extends AbstractController
|
||||
|
||||
$days = $this->calendarService->getAllDays($startDate, $endDate);
|
||||
$days = $this->calendarService->processAbsences($days, $absences);
|
||||
|
||||
$entityHistory = $this->homeAssistantClient->getEntityStateHistory(
|
||||
'person.tim',
|
||||
new DateTimeImmutable('-1 year'),
|
||||
new DateTimeImmutable('+180 days')
|
||||
);
|
||||
|
||||
$icsContent = $this->calendarExportService->generateIcsContent($days, $absences);
|
||||
$icsContent = $this->calendarExportService->generateIcsContent($days, $entityHistory, $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"');
|
||||
//$response->headers->set('Content-Type', 'text/calendar; charset=utf-8');
|
||||
//$response->headers->set('Content-Disposition', 'attachment; filename="work_calendar.ics"');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ final readonly class HomeAssistantClient
|
||||
'filter_entity_id' => $entityId,
|
||||
]);
|
||||
|
||||
return $this->request('GET', "/api/history/period/{$startDate->format('Y-m-d\TH:i:s\Z')}?{$queryParams}");
|
||||
return $this->request('GET', "/api/history/period/{$startDate->format('Y-m-d\TH:i:s\Z')}?{$queryParams}")[0];
|
||||
}
|
||||
|
||||
public function callService(string $domain, string $service, array $data = []): array
|
||||
|
||||
@ -14,7 +14,6 @@ final class CalendarExportService
|
||||
private const KAMEN_ADDRESS = 'Privat \nHeidkamp 21\n59174 Kamen\nDeutschland';
|
||||
private const COMPANY_NAME = 'CHECK24';
|
||||
private const TIMEZONE = 'Europe/Berlin';
|
||||
private const PERSON_ENTITY = 'person.tim';
|
||||
private const OFFICE_STATE = 'CHECK24';
|
||||
|
||||
public function __construct(
|
||||
@ -22,7 +21,7 @@ final class CalendarExportService
|
||||
) {
|
||||
}
|
||||
|
||||
public function generateIcsContent(array $days, array $absences): string
|
||||
public function generateIcsContent(array $days, array $entityHistory, array $absences): string
|
||||
{
|
||||
$icsContent = [
|
||||
'BEGIN:VCALENDAR',
|
||||
@ -39,7 +38,14 @@ final class CalendarExportService
|
||||
}
|
||||
|
||||
$dayDate = clone $day['date'];
|
||||
$startAndEndTimes = $this->getWorkTimesFromHomeAssistant($dayDate);
|
||||
$startOfDay = DateTimeImmutable::createFromInterface($dayDate)->setTime(0, 0, 0);
|
||||
$typicalEndOfDay = DateTimeImmutable::createFromInterface($dayDate)->setTime(17, 30, 0);
|
||||
|
||||
$filteredEntityHistory = array_filter($entityHistory, function (array $state) use ($startOfDay, $typicalEndOfDay) {
|
||||
return $state['last_changed'] >= $startOfDay && $state['last_changed'] <= $typicalEndOfDay;
|
||||
});
|
||||
|
||||
$startAndEndTimes = $this->getWorkTimesFromHomeAssistant($filteredEntityHistory, $dayDate);
|
||||
|
||||
if ($startAndEndTimes === null) {
|
||||
$eventStart = clone $day['date'];
|
||||
@ -74,17 +80,9 @@ final class CalendarExportService
|
||||
return implode("\r\n", $icsContent);
|
||||
}
|
||||
|
||||
private function getWorkTimesFromHomeAssistant(DateTimeInterface $date): ?array
|
||||
private function getWorkTimesFromHomeAssistant(array $stateHistory, DateTimeInterface $date): ?array
|
||||
{
|
||||
$startOfDay = DateTimeImmutable::createFromInterface($date)->setTime(0, 0, 0);
|
||||
$typicalEndOfDay = DateTimeImmutable::createFromInterface($date)->setTime(17, 30, 0);
|
||||
|
||||
try {
|
||||
$stateHistory = $this->homeAssistantClient->getEntityStateHistory(
|
||||
self::PERSON_ENTITY,
|
||||
$startOfDay,
|
||||
$typicalEndOfDay
|
||||
);
|
||||
|
||||
if (empty($stateHistory) || empty($stateHistory[0])) {
|
||||
return null;
|
||||
|
||||
73
src/Service/CalendarStorageService.php
Normal file
73
src/Service/CalendarStorageService.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use DateTime;
|
||||
use RuntimeException;
|
||||
|
||||
final class CalendarStorageService
|
||||
{
|
||||
private const STORAGE_FILE = 'storage/past_events.json';
|
||||
|
||||
/**
|
||||
* Store past events in the storage file
|
||||
*/
|
||||
public function storePastEvents(array $events): void
|
||||
{
|
||||
$dataDirectory = dirname(self::STORAGE_FILE);
|
||||
|
||||
if (!is_dir($dataDirectory)) {
|
||||
if (mkdir($dataDirectory, 0777, true) === false) {
|
||||
throw new RuntimeException('Failed to create storage directory');
|
||||
}
|
||||
}
|
||||
|
||||
if (file_put_contents(self::STORAGE_FILE, json_encode($events)) === false) {
|
||||
throw new RuntimeException('Failed to write past events to storage file');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get past events from the storage file
|
||||
*/
|
||||
public function getPastEvents(): array
|
||||
{
|
||||
if (!file_exists(self::STORAGE_FILE)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$content = file_get_contents(self::STORAGE_FILE);
|
||||
|
||||
if ($content === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$events = json_decode($content, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if past events need to be updated by comparing with cutoff date
|
||||
*/
|
||||
public function shouldUpdatePastEvents(DateTime $cutoffDate): bool
|
||||
{
|
||||
if (!file_exists(self::STORAGE_FILE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fileModTime = filemtime(self::STORAGE_FILE);
|
||||
|
||||
if ($fileModTime === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fileModDate = (new DateTime())->setTimestamp($fileModTime);
|
||||
|
||||
return $fileModDate < $cutoffDate;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user