d42d6d5d96
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>
43 lines
1.9 KiB
Python
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,
|
|
}
|