diff --git a/CHANGELOG.md b/CHANGELOG.md index 931f37c..783a80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to AeonDumpManager will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [0.0.3] - 2026-09-17 + +### Added + +- Filter the dump list by date range and sort by date or size; dates use Shopware's locale-aware + formatting. + ## [0.0.2] - 2026-09-21 ### Added @@ -16,18 +25,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `main` is now a protected branch: no direct pushes, merges require the version/changelog check to pass. -## [Unreleased] +## [0.0.1] - 2026-09-15 ### Added -- List, create, and delete SQL database dumps from a Settings admin page (nested under Settings, per - Shopware's [Add Menu Entry](https://developer.shopware.com/docs/v6.6/guides/plugins/plugins/administration/routing-navigation/add-menu-entry.html) - guide) and via `aeon:dump:list`/`aeon:dump:create`/`aeon:dump:remove` console commands. -- Dumps are created with `mysqldump`/`mariadb-dump` (auto-detected, with an optional `dumpBinaryName` - override), gzip-compressed, and stored in the plugin's private Flysystem mount. -- `maxDumps` auto-purges the oldest dump on creation; `retantionDays` purges dumps and stale job rows - on a recurring scheduled task. -- Admin UI dump creation runs asynchronously via Symfony Messenger with a polling progress bar; console - creation runs synchronously. -- ACL-gated (`aeon_dump_manager.viewer`/`.creator`/`.deleter`), enforced both client-side and - server-side. +- List, create, delete, and download gzip-compressed SQL dumps from a Settings admin page (async + creation with a polling progress bar) or via the `aeon:dump:list`, `aeon:dump:create`, and + `aeon:dump:remove` console commands (sync). Dumps are produced with `mysqldump`/`mariadb-dump` + (auto-detected, overridable via `dumpBinaryName`) and stored in the plugin's private filesystem. +- Retention controls: `maxDumps` purges the oldest dump when the limit is reached; `retantionDays` + purges expired dumps and stale job rows via a scheduled task. +- ACL-gated by `aeon_dump_manager.viewer`/`.creator`/`.deleter`, enforced client- and server-side. diff --git a/composer.json b/composer.json index adc23b7..9e67cbd 100755 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Export database dumps for Shopware 6 environments.", "type": "shopware-platform-plugin", "license": "MIT", - "version": "0.0.2", + "version": "0.0.3", "keywords": [ "shopware", "shopware6", diff --git a/src/Controller/DumpController.php b/src/Controller/DumpController.php index fe12eb9..16768e4 100644 --- a/src/Controller/DumpController.php +++ b/src/Controller/DumpController.php @@ -11,6 +11,7 @@ use Shopware\Core\Framework\Routing\ApiRouteScope; use Shopware\Core\PlatformRequest; use Symfony\Component\HttpFoundation\HeaderUtils; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -39,16 +40,46 @@ class DumpController defaults: [PlatformRequest::ATTRIBUTE_ACL => ['aeon_dump_manager.viewer']], methods: ['GET'] )] - public function list(): JsonResponse + public function list(Request $request): JsonResponse { $dumps = array_map( static fn ($dumpFile) => $dumpFile->jsonSerialize(), - $this->dumpLister->list() + $this->dumpLister->list( + $this->parseBoundDate($request->query->get('from'), false), + $this->parseBoundDate($request->query->get('to'), true), + ) ); return new JsonResponse(['dumps' => $dumps]); } + /** + * The admin's date filter sends mixed shapes: the "from" bound is a naive local + * date string with no timezone marker (e.g. "2026-03-01T00:00:00"), while + * sw-date-filter widens "to" to end-of-day client-side via `Date#toISOString()`, + * which is always UTC (e.g. "2026-03-01T23:59:59.000Z"). Re-expressing both in + * PHP's default timezone (the same one DumpFilenameParser uses) before applying + * our own day-boundary keeps the calendar day the user actually picked, regardless + * of which shape arrived. An empty bound (no date set) stays null so the range is + * open on that side. + */ + private function parseBoundDate(?string $value, bool $endOfDay): ?\DateTimeImmutable + { + if ($value === null || trim($value) === '') { + return null; + } + + try { + $dateTime = (new \DateTimeImmutable($value))->setTimezone(new \DateTimeZone(date_default_timezone_get())); + } catch (\Exception) { + return null; + } + + return $endOfDay + ? $dateTime->setTime(23, 59, 59) + : $dateTime->setTime(0, 0, 0); + } + #[Route( path: '/api/_action/aeon-dump-manager/dumps', name: 'api.action.aeon_dump_manager.dumps.create', diff --git a/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig b/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig index 2d00b1a..5e03557 100644 --- a/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig +++ b/src/Resources/app/administration/src/module/aeon-dump-manager/page/aeon-dump-manager-list/aeon-dump-manager-list.html.twig @@ -14,14 +14,24 @@