Remove maintenance feature
This commit is contained in:
@@ -10,7 +10,7 @@ namespace dokuwiki\plugin\luxtools;
|
||||
*/
|
||||
class CalendarEvent
|
||||
{
|
||||
/** @var string Calendar slot key (e.g. 'general', 'maintenance') */
|
||||
/** @var string Calendar slot key (e.g. 'general', 'slot2') */
|
||||
public $slotKey;
|
||||
|
||||
/** @var string Unique source event UID */
|
||||
@@ -52,35 +52,4 @@ class CalendarEvent
|
||||
|
||||
/** @var string The date (YYYY-MM-DD) this event applies to */
|
||||
public $dateIso;
|
||||
|
||||
/**
|
||||
* Build a stable completion key for maintenance task tracking.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function completionKey(): string
|
||||
{
|
||||
return implode('|', [$this->slotKey, $this->uid, $this->dateIso]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this event/task is marked as completed.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompleted(): bool
|
||||
{
|
||||
$s = strtoupper($this->status);
|
||||
return $s === 'COMPLETED';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this event/task is open (for maintenance filtering).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isOpen(): bool
|
||||
{
|
||||
return !$this->isCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,17 +14,13 @@ use Throwable;
|
||||
/**
|
||||
* Slot-aware calendar service.
|
||||
*
|
||||
* Provides normalized event data grouped by slot for rendering,
|
||||
* widget indicators, task list queries, and completion tracking.
|
||||
* Provides normalized event data grouped by slot for rendering and widget indicators.
|
||||
*/
|
||||
class CalendarService
|
||||
{
|
||||
/** @var array<string,CalendarEvent[]> In-request cache keyed by "slotKey|dateIso" */
|
||||
protected static $dayCache = [];
|
||||
|
||||
/** @var array<string,CalendarEvent[]> In-request cache keyed by "slotKey|all" for open tasks */
|
||||
protected static $taskCache = [];
|
||||
|
||||
/** @var array<string,VCalendar|null> In-request cache keyed by file path */
|
||||
protected static $vcalCache = [];
|
||||
|
||||
@@ -111,81 +107,6 @@ class CalendarService
|
||||
return self::slotEventsForDate($slot, $dateIso) !== [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all open maintenance tasks due up to (and including) today.
|
||||
*
|
||||
* @param CalendarSlot $maintenanceSlot
|
||||
* @param string $todayIso YYYY-MM-DD
|
||||
* @param int $pastDays Maximum number of overdue days to include
|
||||
* @return CalendarEvent[] Sorted: overdue first, then today, then by title
|
||||
*/
|
||||
public static function openMaintenanceTasks(CalendarSlot $maintenanceSlot, string $todayIso, int $pastDays = 30): array
|
||||
{
|
||||
if (!$maintenanceSlot->isEnabled()) return [];
|
||||
if (!ChronoID::isIsoDate($todayIso)) return [];
|
||||
|
||||
$pastDays = max(0, $pastDays);
|
||||
|
||||
$file = $maintenanceSlot->getFile();
|
||||
if ($file === '' || !is_file($file) || !is_readable($file)) return [];
|
||||
|
||||
$cacheKey = $maintenanceSlot->getKey() . '|tasks|' . $todayIso . '|' . $pastDays;
|
||||
if (isset(self::$taskCache[$cacheKey])) {
|
||||
return self::$taskCache[$cacheKey];
|
||||
}
|
||||
|
||||
$tasks = self::parseAllTasksFromFile($file, $maintenanceSlot->getKey(), $todayIso);
|
||||
$oldestOpenDateIso = self::oldestOpenTaskDate($todayIso, $pastDays);
|
||||
|
||||
// Filter: only non-completed, due today or earlier, and not older than the configured overdue window.
|
||||
$open = [];
|
||||
foreach ($tasks as $task) {
|
||||
if ($task->isCompleted()) continue;
|
||||
if ($task->dateIso > $todayIso) continue;
|
||||
if ($task->dateIso < $oldestOpenDateIso) continue;
|
||||
$open[] = $task;
|
||||
}
|
||||
|
||||
// Sort: overdue first, then today, then by time, then by title
|
||||
usort($open, static function (CalendarEvent $a, CalendarEvent $b) use ($todayIso): int {
|
||||
$aOverdue = $a->dateIso < $todayIso;
|
||||
$bOverdue = $b->dateIso < $todayIso;
|
||||
if ($aOverdue !== $bOverdue) {
|
||||
return $aOverdue ? -1 : 1;
|
||||
}
|
||||
$dateCmp = strcmp($a->dateIso, $b->dateIso);
|
||||
if ($dateCmp !== 0) return $dateCmp;
|
||||
|
||||
$timeCmp = strcmp($a->time, $b->time);
|
||||
if ($timeCmp !== 0) return $timeCmp;
|
||||
|
||||
return strcmp($a->summary, $b->summary);
|
||||
});
|
||||
|
||||
self::$taskCache[$cacheKey] = $open;
|
||||
return $open;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $todayIso
|
||||
* @param int $pastDays
|
||||
* @return string
|
||||
*/
|
||||
protected static function oldestOpenTaskDate(string $todayIso, int $pastDays): string
|
||||
{
|
||||
try {
|
||||
$today = new DateTimeImmutable($todayIso . ' 00:00:00', new DateTimeZone('UTC'));
|
||||
} catch (Throwable $e) {
|
||||
return $todayIso;
|
||||
}
|
||||
|
||||
if ($pastDays === 0) {
|
||||
return $today->format('Y-m-d');
|
||||
}
|
||||
|
||||
return $today->sub(new DateInterval('P' . $pastDays . 'D'))->format('Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get slot-level day indicator data for a whole month.
|
||||
*
|
||||
@@ -329,49 +250,6 @@ class CalendarService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse all tasks (VEVENT with STATUS) from a maintenance file,
|
||||
* expanding recurrences up to the given date.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $slotKey
|
||||
* @param string $todayIso
|
||||
* @return CalendarEvent[]
|
||||
*/
|
||||
protected static function parseAllTasksFromFile(string $file, string $slotKey, string $todayIso): array
|
||||
{
|
||||
$calendar = self::readCalendar($file);
|
||||
if ($calendar === null) return [];
|
||||
|
||||
try {
|
||||
$component = $calendar;
|
||||
|
||||
// Expand from a reasonable lookback to tomorrow
|
||||
$utc = new DateTimeZone('UTC');
|
||||
$rangeStart = new DateTimeImmutable('2020-01-01 00:00:00', $utc);
|
||||
$rangeEnd = new DateTimeImmutable($todayIso . ' 00:00:00', $utc);
|
||||
$rangeEnd = $rangeEnd->add(new DateInterval('P1D'));
|
||||
|
||||
$expanded = $component->expand($rangeStart, $rangeEnd);
|
||||
if (!($expanded instanceof VCalendar)) return [];
|
||||
|
||||
$tasks = [];
|
||||
|
||||
// Collect VEVENTs
|
||||
foreach ($expanded->select('VEVENT') as $vevent) {
|
||||
if (!($vevent instanceof VEvent)) continue;
|
||||
$event = self::normalizeVEvent($vevent, $slotKey);
|
||||
if ($event !== null) {
|
||||
$tasks[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
} catch (Throwable $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect normalized events from an expanded VCalendar for a specific date.
|
||||
*
|
||||
@@ -440,42 +318,6 @@ class CalendarService
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a VEVENT into a CalendarEvent (without day filtering).
|
||||
*
|
||||
* @param VEvent $vevent
|
||||
* @param string $slotKey
|
||||
* @return CalendarEvent|null
|
||||
*/
|
||||
protected static function normalizeVEvent(VEvent $vevent, string $slotKey): ?CalendarEvent
|
||||
{
|
||||
if (!isset($vevent->DTSTART)) return null;
|
||||
|
||||
$isAllDay = strtoupper((string)($vevent->DTSTART['VALUE'] ?? '')) === 'DATE';
|
||||
$start = self::toImmutable($vevent->DTSTART->getDateTime());
|
||||
if ($start === null) return null;
|
||||
|
||||
$end = self::resolveEnd($vevent, $start, $isAllDay);
|
||||
|
||||
$event = new CalendarEvent();
|
||||
$event->slotKey = $slotKey;
|
||||
$event->uid = trim((string)($vevent->UID ?? ''));
|
||||
$event->recurrenceId = isset($vevent->{'RECURRENCE-ID'}) ? trim((string)$vevent->{'RECURRENCE-ID'}) : '';
|
||||
$event->summary = trim((string)($vevent->SUMMARY ?? ''));
|
||||
if ($event->summary === '') $event->summary = '(ohne Titel)';
|
||||
$event->startIso = $start->format(DateTimeInterface::ATOM);
|
||||
$event->endIso = $end->format(DateTimeInterface::ATOM);
|
||||
$event->allDay = $isAllDay;
|
||||
$event->time = $isAllDay ? '' : $start->format('H:i');
|
||||
$event->location = trim((string)($vevent->LOCATION ?? ''));
|
||||
$event->description = trim((string)($vevent->DESCRIPTION ?? ''));
|
||||
$event->status = strtoupper(trim((string)($vevent->STATUS ?? '')));
|
||||
$event->componentType = 'VEVENT';
|
||||
$event->dateIso = $start->format('Y-m-d');
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the end date/time for a VEVENT.
|
||||
*
|
||||
@@ -573,7 +415,6 @@ class CalendarService
|
||||
public static function clearCache(): void
|
||||
{
|
||||
self::$dayCache = [];
|
||||
self::$taskCache = [];
|
||||
self::$vcalCache = [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@ namespace dokuwiki\plugin\luxtools;
|
||||
class CalendarSlot
|
||||
{
|
||||
/** @var string[] Ordered list of all supported slot keys */
|
||||
public const SLOT_KEYS = ['general', 'maintenance', 'slot3', 'slot4'];
|
||||
public const SLOT_KEYS = ['general', 'slot2', 'slot3', 'slot4'];
|
||||
|
||||
/** @var string[] Allowed widget indicator display positions */
|
||||
public const INDICATOR_DISPLAYS = ['none', 'top-left', 'top-right', 'bottom-left', 'bottom-right'];
|
||||
|
||||
/** @var array<string,string> Human-readable labels for slot keys */
|
||||
public const SLOT_LABELS = [
|
||||
'general' => 'General',
|
||||
'maintenance' => 'Maintenance',
|
||||
'slot3' => 'Slot 3',
|
||||
'slot4' => 'Slot 4',
|
||||
'general' => 'General',
|
||||
'slot2' => 'Slot 2',
|
||||
'slot3' => 'Slot 3',
|
||||
'slot4' => 'Slot 4',
|
||||
];
|
||||
|
||||
/** @var string */
|
||||
|
||||
Reference in New Issue
Block a user