snapshot: preserve backup UX, remote target setup, and docs updates
This commit is contained in:
@@ -18,6 +18,7 @@ from django.utils import timezone
|
||||
from django.utils.translation import gettext as _, gettext_lazy
|
||||
from django.utils.translation import get_language, override
|
||||
|
||||
from .backup_ops import create_backup_bundle, delete_backup_bundle, list_backup_bundles, verify_backup_bundle
|
||||
from .forms import OffboardingRequestForm, OnboardingRequestForm
|
||||
from .form_builder import (
|
||||
DEFAULT_FIELD_ORDER,
|
||||
@@ -217,6 +218,10 @@ def _audit_action_label(action: str) -> str:
|
||||
'mail_settings_saved': _('Mail-Einstellungen gespeichert'),
|
||||
'email_routing_saved': _('E-Mail-Routing gespeichert'),
|
||||
'notification_rules_saved': _('Benachrichtigungsregeln gespeichert'),
|
||||
'backup_created': _('Backup erstellt'),
|
||||
'backup_verified': _('Backup verifiziert'),
|
||||
'backup_deleted': _('Backup gelöscht'),
|
||||
'backup_settings_saved': _('Backup-Einstellungen gespeichert'),
|
||||
}
|
||||
return labels.get(action, action.replace('_', ' ').strip().capitalize())
|
||||
|
||||
@@ -375,6 +380,75 @@ def audit_log_page(request):
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
def backup_recovery_page(request):
|
||||
return render(
|
||||
request,
|
||||
'workflows/backup_recovery.html',
|
||||
{
|
||||
'rows': list_backup_bundles(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
def create_backup_from_admin(request):
|
||||
try:
|
||||
result = create_backup_bundle()
|
||||
_audit(
|
||||
request,
|
||||
'backup_created',
|
||||
target_type='backup_bundle',
|
||||
target_label=result['name'],
|
||||
details={'path': result['path']},
|
||||
)
|
||||
messages.success(request, _('Backup wurde erstellt: %(name)s') % {'name': result['name']})
|
||||
except Exception as exc:
|
||||
messages.error(request, _('Backup konnte nicht erstellt werden: %(error)s') % {'error': exc})
|
||||
return redirect('backup_recovery_page')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
def verify_backup_from_admin(request, backup_name: str):
|
||||
try:
|
||||
result = verify_backup_bundle(backup_name)
|
||||
_audit(
|
||||
request,
|
||||
'backup_verified',
|
||||
target_type='backup_bundle',
|
||||
target_label=backup_name,
|
||||
details={'summary': result['summary']},
|
||||
)
|
||||
messages.success(request, _('Backup wurde verifiziert: %(name)s') % {'name': result['name']})
|
||||
except Exception as exc:
|
||||
messages.error(request, _('Backup-Verifikation fehlgeschlagen: %(error)s') % {'error': exc})
|
||||
return redirect('backup_recovery_page')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
def delete_backup_from_admin(request, backup_name: str):
|
||||
try:
|
||||
result = delete_backup_bundle(backup_name)
|
||||
_audit(
|
||||
request,
|
||||
'backup_deleted',
|
||||
target_type='backup_bundle',
|
||||
target_label=backup_name,
|
||||
details={},
|
||||
)
|
||||
messages.success(request, _('Backup wurde gelöscht: %(name)s') % {'name': result['name']})
|
||||
except Exception as exc:
|
||||
messages.error(request, _('Backup konnte nicht gelöscht werden: %(error)s') % {'error': exc})
|
||||
return redirect('backup_recovery_page')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
def request_timeline_page(request, kind: str, request_id: int):
|
||||
@@ -1242,7 +1316,7 @@ def intro_builder_page(request):
|
||||
def integrations_setup_page(request):
|
||||
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
||||
kind = (request.GET.get('kind') or 'nextcloud').strip().lower()
|
||||
if kind not in {'nextcloud', 'mail', 'emails', 'rules'}:
|
||||
if kind not in {'nextcloud', 'mail', 'emails', 'rules', 'backup'}:
|
||||
kind = 'nextcloud'
|
||||
templates = list(NotificationTemplate.objects.all().order_by('key'))
|
||||
system_email_config = (
|
||||
@@ -1263,6 +1337,7 @@ def integrations_setup_page(request):
|
||||
'rule_event_choices': NotificationRule.EVENT_CHOICES,
|
||||
'rule_operator_choices': NotificationRule.OPERATOR_CHOICES,
|
||||
'template_choices': NotificationTemplate.TEMPLATE_CHOICES,
|
||||
'remote_backup_target_choices': WorkflowConfig.REMOTE_BACKUP_TARGET_CHOICES,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1794,12 +1869,67 @@ def save_workflow_rules(request):
|
||||
'workflow_rules_saved',
|
||||
target_type='workflow_config',
|
||||
target_label='workflow_rules',
|
||||
details={'device_handover_lead_days': config.device_handover_lead_days},
|
||||
details={
|
||||
'device_handover_lead_days': config.device_handover_lead_days,
|
||||
},
|
||||
)
|
||||
messages.success(request, 'Workflow-Regeln wurden gespeichert.')
|
||||
return redirect('/admin-tools/integrations/?kind=rules')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
def save_backup_settings(request):
|
||||
config, _ = WorkflowConfig.objects.get_or_create(name='Default')
|
||||
target_type = (request.POST.get('remote_backup_target_type') or config.remote_backup_target_type or 'nextcloud').strip().lower()
|
||||
if target_type not in {choice for choice, _ in WorkflowConfig.REMOTE_BACKUP_TARGET_CHOICES}:
|
||||
target_type = 'nextcloud'
|
||||
remote_backup_enabled = request.POST.get('remote_backup_enabled') == 'on'
|
||||
remote_backup_nextcloud_directory = request.POST.get('remote_backup_nextcloud_directory', '').strip()
|
||||
primary_nextcloud_directory = (
|
||||
(config.nextcloud_directory_override or '').strip()
|
||||
or settings.NEXTCLOUD_DIRECTORY.strip()
|
||||
).strip('/')
|
||||
|
||||
if remote_backup_enabled and target_type == 'nextcloud':
|
||||
if not remote_backup_nextcloud_directory:
|
||||
messages.error(request, 'Bitte ein separates Nextcloud Backup-Verzeichnis angeben.')
|
||||
return redirect('/admin-tools/integrations/?kind=backup')
|
||||
if remote_backup_nextcloud_directory.strip('/') == primary_nextcloud_directory:
|
||||
messages.error(request, 'Das Backup-Verzeichnis muss vom normalen Nextcloud Dokumentenordner getrennt sein.')
|
||||
return redirect('/admin-tools/integrations/?kind=backup')
|
||||
|
||||
config.remote_backup_enabled = remote_backup_enabled
|
||||
config.remote_backup_target_type = target_type
|
||||
config.remote_backup_nextcloud_directory = remote_backup_nextcloud_directory
|
||||
config.remote_backup_s3_bucket = request.POST.get('remote_backup_s3_bucket', '').strip()
|
||||
config.remote_backup_nfs_path = request.POST.get('remote_backup_nfs_path', '').strip()
|
||||
config.save(
|
||||
update_fields=[
|
||||
'device_handover_lead_days',
|
||||
'remote_backup_enabled',
|
||||
'remote_backup_target_type',
|
||||
'remote_backup_nextcloud_directory',
|
||||
'remote_backup_s3_bucket',
|
||||
'remote_backup_nfs_path',
|
||||
]
|
||||
)
|
||||
_audit(
|
||||
request,
|
||||
'backup_settings_saved',
|
||||
target_type='workflow_config',
|
||||
target_label='backup_settings',
|
||||
details={
|
||||
'remote_backup_enabled': config.remote_backup_enabled,
|
||||
'remote_backup_target_type': config.remote_backup_target_type,
|
||||
'remote_backup_nextcloud_directory': config.remote_backup_nextcloud_directory,
|
||||
},
|
||||
)
|
||||
messages.success(request, 'Backup-Einstellungen wurden gespeichert.')
|
||||
return redirect('/admin-tools/integrations/?kind=backup')
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(_is_staff)
|
||||
@require_POST
|
||||
|
||||
Reference in New Issue
Block a user