push
This commit is contained in:
66
app/services/backup_service.py
Normal file
66
app/services/backup_service.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
from flask import current_app
|
||||
|
||||
|
||||
class BackupService:
|
||||
def create_backup(self):
|
||||
target = Path(current_app.config['BACKUP_PATH']) / f'backup_{datetime.utcnow().strftime("%Y%m%d_%H%M%S")}'
|
||||
target.mkdir(parents=True, exist_ok=True)
|
||||
base_dir = Path(current_app.root_path).parent
|
||||
for part in ['instance', 'storage/archive', 'storage/pdf']:
|
||||
src = base_dir / part
|
||||
if src.exists():
|
||||
shutil.copytree(src, target / Path(part).name, dirs_exist_ok=True)
|
||||
archive = shutil.make_archive(str(target), 'zip', root_dir=target)
|
||||
return archive
|
||||
|
||||
def get_database_backup_meta(self) -> dict:
|
||||
uri = current_app.config.get('SQLALCHEMY_DATABASE_URI', '')
|
||||
backup_dir = Path(current_app.config['BACKUP_PATH'])
|
||||
engine = 'unknown'
|
||||
if '://' in uri:
|
||||
engine = uri.split('://', 1)[0]
|
||||
sqlite_supported = uri.startswith('sqlite:///') and not uri.endswith(':memory:')
|
||||
sqlite_path = None
|
||||
sqlite_exists = False
|
||||
if sqlite_supported:
|
||||
sqlite_path = Path(uri.replace('sqlite:///', '', 1))
|
||||
sqlite_exists = sqlite_path.exists()
|
||||
return {
|
||||
'engine': engine,
|
||||
'backup_dir': str(backup_dir),
|
||||
'sqlite_supported': sqlite_supported,
|
||||
'sqlite_path': str(sqlite_path) if sqlite_path else None,
|
||||
'sqlite_exists': sqlite_exists,
|
||||
'notes': [
|
||||
'Kopia z panelu działa plikowo dla SQLite.',
|
||||
'Dla PostgreSQL, MySQL i innych silników wymagany jest natywny dump bazy poza aplikacją.',
|
||||
],
|
||||
}
|
||||
|
||||
def create_database_backup(self) -> str:
|
||||
target_dir = Path(current_app.config['BACKUP_PATH'])
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
timestamp = datetime.utcnow().strftime('%Y%m%d_%H%M%S')
|
||||
uri = current_app.config.get('SQLALCHEMY_DATABASE_URI', '')
|
||||
if uri.startswith('sqlite:///') and not uri.endswith(':memory:'):
|
||||
source = Path(uri.replace('sqlite:///', '', 1))
|
||||
if not source.exists():
|
||||
raise FileNotFoundError(f'Plik bazy nie istnieje: {source}')
|
||||
target = target_dir / f'db_backup_{timestamp}.sqlite3'
|
||||
shutil.copy2(source, target)
|
||||
return str(target)
|
||||
target = target_dir / f'db_backup_{timestamp}.txt'
|
||||
target.write_text(
|
||||
"""Automatyczna kopia DB dla bieżącego silnika nie jest obsługiwana plikowo.
|
||||
W panelu admina kopia działa bezpośrednio tylko dla SQLite.
|
||||
Wykonaj backup natywnym narzędziem bazy danych.
|
||||
""",
|
||||
encoding='utf-8',
|
||||
)
|
||||
return str(target)
|
||||
Reference in New Issue
Block a user