Add backup restore feature

- Add restoreBackup() method to UpdateExecutor with full restore workflow
- Add getBackupDetails() to retrieve backup metadata and contents info
- Add restore controller routes (backup details API, restore action)
- Add restore button to backups table in UI
- Create backup_restore_controller.js Stimulus controller for confirmation
- Add translation strings for restore feature

The restore process:
1. Acquires lock and enables maintenance mode
2. Extracts backup to temp directory
3. Restores database (MySQL/PostgreSQL SQL or SQLite file)
4. Optionally restores config files and attachments
5. Clears and warms cache
6. Disables maintenance mode

Fix backup restore database import

The restore feature was using a non-existent doctrine:database:import
command. Now properly uses mysql/psql commands directly to import
database dumps.

Changes:
- Add EntityManagerInterface dependency to UpdateExecutor
- Use mysql command with shell input redirection for MySQL restore
- Use psql -f command for PostgreSQL restore
- Properly handle database connection parameters
- Add error handling for failed imports
This commit is contained in:
Sebastian Almberg 2026-01-30 22:51:25 +01:00
parent 0bfbbc961d
commit 1637fd63f4
5 changed files with 499 additions and 2 deletions

View file

@ -342,6 +342,7 @@
<th>{% trans %}update_manager.date{% endtrans %}</th>
<th>{% trans %}update_manager.file{% endtrans %}</th>
<th>{% trans %}update_manager.size{% endtrans %}</th>
<th></th>
</tr>
</thead>
<tbody>
@ -354,10 +355,30 @@
<td class="text-muted small">
{{ (backup.size / 1024 / 1024)|number_format(1) }} MB
</td>
<td class="text-end">
{% if status.can_auto_update and validation.valid %}
<form action="{{ path('admin_update_manager_restore') }}" method="post" class="d-inline"
data-controller="backup-restore"
data-backup-restore-filename-value="{{ backup.file }}"
data-backup-restore-date-value="{{ backup.date|date('Y-m-d H:i') }}"
data-backup-restore-confirm-title-value="{{ 'update_manager.restore_confirm_title'|trans }}"
data-backup-restore-confirm-message-value="{{ 'update_manager.restore_confirm_message'|trans }}"
data-backup-restore-confirm-warning-value="{{ 'update_manager.restore_confirm_warning'|trans }}">
<input type="hidden" name="_token" value="{{ csrf_token('update_manager_restore') }}">
<input type="hidden" name="filename" value="{{ backup.file }}">
<input type="hidden" name="restore_database" value="1">
<button type="submit"
class="btn btn-sm btn-outline-warning"
title="{% trans %}update_manager.restore_backup{% endtrans %}">
<i class="fas fa-undo"></i>
</button>
</form>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="3" class="text-center text-muted py-3">
<td colspan="4" class="text-center text-muted py-3">
{% trans %}update_manager.no_backups_found{% endtrans %}
</td>
</tr>