Files
minmal-file-cloud-email-pim…/backend/app/models/backup_target.py
T
Stefan Hacker d42d6d5d96 feat: SFTP-Backup mit Scheduler, Versionierung und Multi-Target
Mehrere SFTP-Backup-Ziele konfigurierbar mit:
- Host, Port, Benutzername, Passwort, Remote-Pfad
- Konfigurierbares Intervall (15 Min. bis woechentlich oder deaktiviert)
- Maximale Anzahl aufbewahrter Versionen (aeltere werden automatisch geloescht)
- Aktiv/Inaktiv-Toggle pro Ziel

Features:
- Automatischer Hintergrund-Scheduler prueft alle 60 Sekunden ob
  Backups faellig sind und fuehrt sie aus
- Manuelles Backup per Klick ("Jetzt sichern")
- SFTP-Verbindungstest-Button
- Versionen-Dialog: Alle Backup-Versionen auf dem SFTP-Server auflisten
  mit Groesse und Datum
- Restore direkt von SFTP: Version auswaehlen -> wird heruntergeladen
  und ueber die bestehende DB-Merge-Logik wiederhergestellt
- Chunked Upload zum SFTP in 16MB-Bloecken (fuer grosse Backups)
- Status-Anzeige: Letztes Backup, Erfolg/Fehler, Nachricht

Backend: BackupTarget Model, SFTP-Service (paramiko), Backup-Scheduler
API: /admin/backup/targets CRUD, /test, /run, /versions, /restore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 18:07:28 +02:00

43 lines
1.9 KiB
Python

from datetime import datetime, timezone
from app.extensions import db
class BackupTarget(db.Model):
__tablename__ = 'backup_targets'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
host = db.Column(db.String(255), nullable=False)
port = db.Column(db.Integer, default=22)
username = db.Column(db.String(100), nullable=False)
password_encrypted = db.Column(db.LargeBinary, nullable=True)
private_key_encrypted = db.Column(db.LargeBinary, nullable=True)
remote_path = db.Column(db.String(500), default='/backups/minicloud')
is_active = db.Column(db.Boolean, default=True)
backup_interval_minutes = db.Column(db.Integer, default=1440) # Default: daily
max_versions = db.Column(db.Integer, default=10)
last_backup_at = db.Column(db.DateTime, nullable=True)
last_backup_status = db.Column(db.String(20), nullable=True) # 'success', 'error'
last_backup_message = db.Column(db.Text, nullable=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
def to_dict(self):
return {
'id': self.id,
'name': self.name,
'host': self.host,
'port': self.port,
'username': self.username,
'has_password': bool(self.password_encrypted),
'has_private_key': bool(self.private_key_encrypted),
'remote_path': self.remote_path,
'is_active': self.is_active,
'backup_interval_minutes': self.backup_interval_minutes,
'max_versions': self.max_versions,
'last_backup_at': self.last_backup_at.isoformat() if self.last_backup_at else None,
'last_backup_status': self.last_backup_status,
'last_backup_message': self.last_backup_message,
'created_at': self.created_at.isoformat() if self.created_at else None,
}