Fix #109: Ereignisse-Log für Nextcloud-Import
This commit is contained in:
parent
6ce2c72cd9
commit
1fec39da9b
9 changed files with 212 additions and 8 deletions
11
Changes.md
11
Changes.md
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-06-29 – Feature: Ereignisse-Log für Nextcloud-Import (Issue #109)
|
||||||
|
|
||||||
|
- **`migrations/083_system_events.sql`:** Neue Tabelle `system_events` (id, channel, message, created_at)
|
||||||
|
- **`src/Models/EventLog.php`:** Neues Model mit `add()` und `findByChannel()`
|
||||||
|
- **`src/Services/NextcloudImportService.php`:** Persistiert relevante Ereignisse (Import, Duplikat, Fehler) automatisch; stille Läufe ohne Dateiaktivität erzeugen keine Einträge; Zusammenfassung wird nur bei tatsächlicher Aktivität geloggt
|
||||||
|
- **`src/Controllers/EventController.php`:** Neuer Controller für `/ereignisse` und `/ereignisse/nextcloud-import`
|
||||||
|
- **`src/Views/ereignisse/nextcloud_import.php`:** Log-Ansicht mit Zeitstempel, Kanal und farbiger Meldung
|
||||||
|
- **`src/Views/layout/nav.php`:** Neuer Menüpunkt „Ereignisse" unter Verwaltung mit aufklappbarem Unterpunkt „Nextcloud-Import"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-06-29 – Feature: Lieferant in Belegliste inline bearbeiten (Issue #108)
|
## 2026-06-29 – Feature: Lieferant in Belegliste inline bearbeiten (Issue #108)
|
||||||
|
|
||||||
- **`src/Views/belege/list.php`:** Lieferant-Spalte ist direkt in der Liste klickbar; zeigt ein Inline-Textfeld zur Eingabe, speichert mit Enter, bricht mit Escape ab; andere Spalten öffnen weiterhin die Vorschau
|
- **`src/Views/belege/list.php`:** Lieferant-Spalte ist direkt in der Liste klickbar; zeigt ein Inline-Textfeld zur Eingabe, speichert mit Enter, bricht mit Escape ab; andere Spalten öffnen weiterhin die Vorschau
|
||||||
|
|
|
||||||
7
migrations/083_system_events.sql
Normal file
7
migrations/083_system_events.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS system_events (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
channel VARCHAR(50) NOT NULL,
|
||||||
|
message TEXT NOT NULL,
|
||||||
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_channel_created (channel, created_at)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
@ -28,6 +28,7 @@ use Steuerkram\Controllers\AssetController;
|
||||||
use Steuerkram\Controllers\UserAdminController;
|
use Steuerkram\Controllers\UserAdminController;
|
||||||
use Steuerkram\Controllers\BankController;
|
use Steuerkram\Controllers\BankController;
|
||||||
use Steuerkram\Controllers\BuchungsvorlageController;
|
use Steuerkram\Controllers\BuchungsvorlageController;
|
||||||
|
use Steuerkram\Controllers\EventController;
|
||||||
|
|
||||||
Config::load();
|
Config::load();
|
||||||
|
|
||||||
|
|
@ -184,6 +185,10 @@ $router->post('/einstellungen/buchungsvorlagen/{id}/loeschen', fn($p) =
|
||||||
$router->get('/api/buchungsvorlagen/{id}/modal', fn($p) => (new BuchungsvorlageController())->modal($p));
|
$router->get('/api/buchungsvorlagen/{id}/modal', fn($p) => (new BuchungsvorlageController())->modal($p));
|
||||||
$router->post('/belege/{belegId}/vorlage/{vorlageId}/buchen', fn($p) => (new BuchungsvorlageController())->buchen($p));
|
$router->post('/belege/{belegId}/vorlage/{vorlageId}/buchen', fn($p) => (new BuchungsvorlageController())->buchen($p));
|
||||||
|
|
||||||
|
// ── Ereignisse ───────────────────────────────────────────────
|
||||||
|
$router->get('/ereignisse', fn($p) => (new EventController())->index($p));
|
||||||
|
$router->get('/ereignisse/nextcloud-import', fn($p) => (new EventController())->nextcloudImport($p));
|
||||||
|
|
||||||
// ── Login / Logout ────────────────────────────────────────────
|
// ── Login / Logout ────────────────────────────────────────────
|
||||||
$router->get('/login', fn($p) => (new LoginController())->showLogin($p));
|
$router->get('/login', fn($p) => (new LoginController())->showLogin($p));
|
||||||
$router->post('/login', fn($p) => (new LoginController())->handleLogin($p));
|
$router->post('/login', fn($p) => (new LoginController())->handleLogin($p));
|
||||||
|
|
|
||||||
29
src/Controllers/EventController.php
Normal file
29
src/Controllers/EventController.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Steuerkram\Controllers;
|
||||||
|
|
||||||
|
use Steuerkram\Models\EventLog;
|
||||||
|
use Steuerkram\View;
|
||||||
|
|
||||||
|
class EventController extends BaseController
|
||||||
|
{
|
||||||
|
public function index(array $params): void
|
||||||
|
{
|
||||||
|
View::redirect('/ereignisse/nextcloud-import');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nextcloudImport(array $params): void
|
||||||
|
{
|
||||||
|
$events = EventLog::findByChannel('nextcloud-import', 500);
|
||||||
|
|
||||||
|
$view = new View();
|
||||||
|
$view->render('layout/base.php', [
|
||||||
|
'pageTitle' => 'Ereignisse – Nextcloud-Import',
|
||||||
|
'content' => $this->renderView('ereignisse/nextcloud_import', [
|
||||||
|
'events' => $events,
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/Models/EventLog.php
Normal file
30
src/Models/EventLog.php
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Steuerkram\Models;
|
||||||
|
|
||||||
|
use Steuerkram\Database;
|
||||||
|
|
||||||
|
class EventLog
|
||||||
|
{
|
||||||
|
public static function add(string $channel, string $message): void
|
||||||
|
{
|
||||||
|
Database::execute(
|
||||||
|
'INSERT INTO system_events (channel, message) VALUES (?, ?)',
|
||||||
|
[$channel, $message]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findByChannel(string $channel, int $limit = 500): array
|
||||||
|
{
|
||||||
|
return Database::fetchAll(
|
||||||
|
'SELECT id, channel, message, created_at
|
||||||
|
FROM system_events
|
||||||
|
WHERE channel = ?
|
||||||
|
ORDER BY created_at DESC, id DESC
|
||||||
|
LIMIT ?',
|
||||||
|
[$channel, $limit]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ namespace Steuerkram\Services;
|
||||||
|
|
||||||
use Steuerkram\Database;
|
use Steuerkram\Database;
|
||||||
use Steuerkram\Models\Beleg;
|
use Steuerkram\Models\Beleg;
|
||||||
|
use Steuerkram\Models\EventLog;
|
||||||
use Steuerkram\Models\Setting;
|
use Steuerkram\Models\Setting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,6 +46,7 @@ class NextcloudImportService
|
||||||
private string $folder;
|
private string $folder;
|
||||||
private string|null $doneFolder;
|
private string|null $doneFolder;
|
||||||
private string $davBase;
|
private string $davBase;
|
||||||
|
private array $pendingEvents = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
@ -69,18 +71,23 @@ class NextcloudImportService
|
||||||
*/
|
*/
|
||||||
public function import(): array
|
public function import(): array
|
||||||
{
|
{
|
||||||
|
$start = microtime(true);
|
||||||
$result = ['imported' => 0, 'skipped' => 0, 'errors' => 0, 'details' => [], 'imported_ids' => []];
|
$result = ['imported' => 0, 'skipped' => 0, 'errors' => 0, 'details' => [], 'imported_ids' => []];
|
||||||
|
|
||||||
if (!$this->baseUrl || !$this->user || !$this->pass) {
|
if (!$this->baseUrl || !$this->user || !$this->pass) {
|
||||||
$result['details'][] = 'FEHLER: NEXTCLOUD_URL, NEXTCLOUD_USER und NEXTCLOUD_PASS müssen gesetzt sein.';
|
$msg = 'FEHLER: NEXTCLOUD_URL, NEXTCLOUD_USER und NEXTCLOUD_PASS müssen gesetzt sein.';
|
||||||
|
$result['details'][] = $msg;
|
||||||
$result['errors']++;
|
$result['errors']++;
|
||||||
|
$this->persistEvent($msg);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
$files = $this->listFiles();
|
$files = $this->listFiles();
|
||||||
if ($files === null) {
|
if ($files === null) {
|
||||||
$result['details'][] = 'FEHLER: PROPFIND fehlgeschlagen. URL/Zugangsdaten prüfen.';
|
$msg = 'FEHLER: PROPFIND fehlgeschlagen. URL/Zugangsdaten prüfen.';
|
||||||
|
$result['details'][] = $msg;
|
||||||
$result['errors']++;
|
$result['errors']++;
|
||||||
|
$this->persistEvent($msg);
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,9 +97,24 @@ class NextcloudImportService
|
||||||
$this->processFile($file, $result);
|
$this->processFile($file, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($result['imported'] + $result['skipped'] + $result['errors'] > 0) {
|
||||||
|
$elapsed = round(microtime(true) - $start, 2);
|
||||||
|
$summary = sprintf(
|
||||||
|
'Fertig in %ss – importiert: %d, übersprungen: %d, Fehler: %d',
|
||||||
|
$elapsed, $result['imported'], $result['skipped'], $result['errors']
|
||||||
|
);
|
||||||
|
$this->persistEvent($summary);
|
||||||
|
$result['details'][] = $summary;
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function persistEvent(string $message): void
|
||||||
|
{
|
||||||
|
EventLog::add('nextcloud-import', $message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listet alle Dateien im konfigurierten Ordner via PROPFIND.
|
* Listet alle Dateien im konfigurierten Ordner via PROPFIND.
|
||||||
* Gibt null zurück bei Verbindungsfehler.
|
* Gibt null zurück bei Verbindungsfehler.
|
||||||
|
|
@ -198,7 +220,9 @@ class NextcloudImportService
|
||||||
|
|
||||||
// MIME prüfen
|
// MIME prüfen
|
||||||
if (!isset(self::ALLOWED_MIME[$contentType])) {
|
if (!isset(self::ALLOWED_MIME[$contentType])) {
|
||||||
$result['details'][] = "Übersprungen (unbekannter Typ «{$contentType}»): {$filename}";
|
$msg = "Übersprungen (unbekannter Typ «{$contentType}»): {$filename}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['skipped']++;
|
$result['skipped']++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +234,9 @@ class NextcloudImportService
|
||||||
$tmpPath = sys_get_temp_dir() . '/nextcloud_import_' . uniqid() . '.' . $ext;
|
$tmpPath = sys_get_temp_dir() . '/nextcloud_import_' . uniqid() . '.' . $ext;
|
||||||
|
|
||||||
if (!$this->downloadFile($fileUrl, $tmpPath)) {
|
if (!$this->downloadFile($fileUrl, $tmpPath)) {
|
||||||
$result['details'][] = "FEHLER beim Download: {$filename}";
|
$msg = "FEHLER beim Download: {$filename}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['errors']++;
|
$result['errors']++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +248,9 @@ class NextcloudImportService
|
||||||
[$rawHash]
|
[$rawHash]
|
||||||
);
|
);
|
||||||
if ($existing) {
|
if ($existing) {
|
||||||
$result['details'][] = "Duplikat (Beleg {$existing['beleg_nr']}): {$filename}";
|
$msg = "Duplikat (Beleg {$existing['beleg_nr']}): {$filename}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['skipped']++;
|
$result['skipped']++;
|
||||||
unlink($tmpPath);
|
unlink($tmpPath);
|
||||||
$this->moveFile($file['href'], $filename);
|
$this->moveFile($file['href'], $filename);
|
||||||
|
|
@ -236,7 +264,9 @@ class NextcloudImportService
|
||||||
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
$absDir = dirname(__DIR__, 2) . "/public/{$relDir}";
|
||||||
|
|
||||||
if (!is_dir($absDir) && !mkdir($absDir, 0755, true)) {
|
if (!is_dir($absDir) && !mkdir($absDir, 0755, true)) {
|
||||||
$result['details'][] = "FEHLER: Verzeichnis konnte nicht erstellt werden: {$absDir}";
|
$msg = "FEHLER: Verzeichnis konnte nicht erstellt werden: {$absDir}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['errors']++;
|
$result['errors']++;
|
||||||
unlink($tmpPath);
|
unlink($tmpPath);
|
||||||
return;
|
return;
|
||||||
|
|
@ -246,7 +276,9 @@ class NextcloudImportService
|
||||||
$absPath = dirname(__DIR__, 2) . "/public/{$storagePath}";
|
$absPath = dirname(__DIR__, 2) . "/public/{$storagePath}";
|
||||||
|
|
||||||
if (!rename($tmpPath, $absPath)) {
|
if (!rename($tmpPath, $absPath)) {
|
||||||
$result['details'][] = "FEHLER: Datei konnte nicht verschoben werden: {$filename}";
|
$msg = "FEHLER: Datei konnte nicht verschoben werden: {$filename}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['errors']++;
|
$result['errors']++;
|
||||||
@unlink($tmpPath);
|
@unlink($tmpPath);
|
||||||
return;
|
return;
|
||||||
|
|
@ -278,7 +310,9 @@ class NextcloudImportService
|
||||||
// Datei in Nextcloud verschieben/löschen
|
// Datei in Nextcloud verschieben/löschen
|
||||||
$this->moveFile($file['href'], $filename);
|
$this->moveFile($file['href'], $filename);
|
||||||
|
|
||||||
$result['details'][] = "Importiert: {$filename} → Beleg {$belegNr}";
|
$msg = "Importiert: {$filename} → Beleg {$belegNr}";
|
||||||
|
$result['details'][] = $msg;
|
||||||
|
$this->persistEvent($msg);
|
||||||
$result['imported']++;
|
$result['imported']++;
|
||||||
$result['imported_ids'][] = $belegId;
|
$result['imported_ids'][] = $belegId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
src/Views/ereignisse/nextcloud_import.php
Normal file
35
src/Views/ereignisse/nextcloud_import.php
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php use Steuerkram\View; $h = fn($v) => View::h($v); ?>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-bottom:1px solid var(--color-border)">
|
||||||
|
<strong>Nextcloud-Import</strong>
|
||||||
|
<span class="text-muted text-sm"><?= count($events) ?> Einträge (neueste zuerst)</span>
|
||||||
|
</div>
|
||||||
|
<?php if (empty($events)): ?>
|
||||||
|
<div style="padding:2rem;text-align:center" class="text-muted">Keine Ereignisse vorhanden. Einträge entstehen, sobald der Nextcloud-Import Dateien importiert, überspringt oder auf Fehler stößt.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div style="overflow-x:auto">
|
||||||
|
<table style="width:100%;border-collapse:collapse;font-size:.875rem">
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ($events as $e): ?>
|
||||||
|
<?php
|
||||||
|
$msg = $e['message'];
|
||||||
|
$isError = str_starts_with($msg, 'FEHLER');
|
||||||
|
$isDup = str_starts_with($msg, 'Duplikat');
|
||||||
|
$isOk = str_starts_with($msg, 'Importiert');
|
||||||
|
$color = $isError ? 'var(--color-danger,#dc2626)'
|
||||||
|
: ($isDup ? 'var(--color-warning,#d97706)'
|
||||||
|
: ($isOk ? 'var(--color-success,#16a34a)'
|
||||||
|
: 'inherit'));
|
||||||
|
?>
|
||||||
|
<tr style="border-bottom:1px solid var(--color-border,#e2e8f0)">
|
||||||
|
<td style="padding:.35rem 1rem;white-space:nowrap;color:var(--color-muted);font-family:monospace"><?= $h(date('Y-m-d H:i:s', strtotime($e['created_at']))) ?></td>
|
||||||
|
<td style="padding:.35rem .5rem;white-space:nowrap;color:var(--color-muted);font-family:monospace">[<?= $h($e['channel']) ?>]</td>
|
||||||
|
<td style="padding:.35rem 1rem;color:<?= $color ?>;word-break:break-word"><?= $h($msg) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
@ -84,6 +84,16 @@ function navActive(string $prefix, string $current): string {
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>
|
||||||
Benutzer
|
Benutzer
|
||||||
</a>
|
</a>
|
||||||
|
<a href="/ereignisse" class="<?= navActive('/ereignisse', $path) ?>">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22V12M12 12L8 16M12 12l4 4"/><circle cx="12" cy="5" r="3"/><path d="M5.5 8.5A7 7 0 0 0 5 12"/><path d="M18.5 8.5A7 7 0 0 1 19 12"/></svg>
|
||||||
|
Ereignisse
|
||||||
|
</a>
|
||||||
|
<?php if (str_starts_with($path, '/ereignisse')): ?>
|
||||||
|
<a href="/ereignisse/nextcloud-import" class="<?= navActive('/ereignisse/nextcloud-import', $path) ?>" style="padding-left:2.25rem;font-size:.875rem">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 16.92V20a2 2 0 0 1-2.18 2A19.79 19.79 0 0 1 11.39 19a19.5 19.5 0 0 1-4.9-4.9 19.79 19.79 0 0 1-3-9.43A2 2 0 0 1 5.32 3H8.4a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L9.4 10.9a16 16 0 0 0 3.71 3.71l1.26-1.26a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
|
||||||
|
Nextcloud-Import
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
<a href="/settings" class="<?= navActive('/settings', $path) ?>">
|
<a href="/settings" class="<?= navActive('/settings', $path) ?>">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93l-1.41 1.41M4.93 4.93l1.41 1.41M19.07 19.07l-1.41-1.41M4.93 19.07l1.41-1.41M12 2v2M12 20v2M2 12h2M20 12h2"/></svg>
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93l-1.41 1.41M4.93 4.93l1.41 1.41M19.07 19.07l-1.41-1.41M4.93 19.07l1.41-1.41M12 2v2M12 20v2M2 12h2M20 12h2"/></svg>
|
||||||
Einstellungen
|
Einstellungen
|
||||||
|
|
|
||||||
43
tests/47_SystemEventsTest.php
Normal file
43
tests/47_SystemEventsTest.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Steuerkram\Models\EventLog;
|
||||||
|
|
||||||
|
class SystemEventsTest extends TestCase
|
||||||
|
{
|
||||||
|
protected string $testName = 'Test 47: EventLog – Einträge schreiben und lesen';
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$channel = 'test-' . uniqid();
|
||||||
|
|
||||||
|
// Kein Eintrag initial
|
||||||
|
$before = EventLog::findByChannel($channel);
|
||||||
|
$this->assertEquals(0, count($before), 'Kanal initial leer');
|
||||||
|
|
||||||
|
// Eintrag anlegen
|
||||||
|
EventLog::add($channel, 'Importiert: test.pdf → Beleg TST-0001');
|
||||||
|
EventLog::add($channel, 'Duplikat (Beleg TST-0001): test.pdf');
|
||||||
|
EventLog::add($channel, 'FEHLER beim Download: fehler.pdf');
|
||||||
|
|
||||||
|
$entries = EventLog::findByChannel($channel);
|
||||||
|
$this->assertEquals(3, count($entries), 'Drei Einträge vorhanden');
|
||||||
|
|
||||||
|
// Neueste zuerst (höchste id zuletzt hinzugefügt)
|
||||||
|
$this->assertEquals('FEHLER beim Download: fehler.pdf', $entries[0]['message'], 'Neuester Eintrag zuerst');
|
||||||
|
$this->assertEquals($channel, $entries[0]['channel'], 'Kanal korrekt gesetzt');
|
||||||
|
|
||||||
|
// created_at vorhanden und parseable
|
||||||
|
$ts = strtotime($entries[0]['created_at']);
|
||||||
|
$this->assert($ts > 0, 'created_at ist ein gültiges Datum');
|
||||||
|
|
||||||
|
// Limit wird eingehalten
|
||||||
|
$limited = EventLog::findByChannel($channel, 2);
|
||||||
|
$this->assertEquals(2, count($limited), 'Limit 2 wird eingehalten');
|
||||||
|
|
||||||
|
// Anderer Kanal bleibt unberührt
|
||||||
|
$other = EventLog::findByChannel('other-channel-' . uniqid());
|
||||||
|
$this->assertEquals(0, count($other), 'Anderer Kanal ist leer');
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue