updated backups solution
This commit is contained in:
@@ -3711,4 +3711,106 @@ def api_backup_restore(filename):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Restore failed: {str(e)}'
|
||||
}), 500
|
||||
}), 500
|
||||
@bp.route('/api/backup/upload', methods=['POST'])
|
||||
@superadmin_only
|
||||
def api_backup_upload():
|
||||
"""Upload an external backup file (superadmin only)"""
|
||||
try:
|
||||
from app.database_backup import DatabaseBackupManager
|
||||
from werkzeug.utils import secure_filename
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# Check if file was uploaded
|
||||
if 'backup_file' not in request.files:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'No file uploaded'
|
||||
}), 400
|
||||
|
||||
file = request.files['backup_file']
|
||||
|
||||
# Check if file was selected
|
||||
if file.filename == '':
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'No file selected'
|
||||
}), 400
|
||||
|
||||
# Validate file extension
|
||||
if not file.filename.lower().endswith('.sql'):
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Invalid file format. Only .sql files are allowed.'
|
||||
}), 400
|
||||
|
||||
# Get backup manager and backup path
|
||||
backup_manager = DatabaseBackupManager()
|
||||
backup_path = backup_manager.backup_path
|
||||
|
||||
# Ensure backup_path is a Path object
|
||||
from pathlib import Path
|
||||
if not isinstance(backup_path, Path):
|
||||
backup_path = Path(backup_path)
|
||||
|
||||
# Create backup directory if it doesn't exist
|
||||
backup_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Generate secure filename with timestamp to avoid conflicts
|
||||
original_filename = secure_filename(file.filename)
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
# If filename already starts with "backup_", keep it; otherwise add prefix
|
||||
if original_filename.startswith('backup_'):
|
||||
new_filename = f"{original_filename.rsplit('.', 1)[0]}_{timestamp}.sql"
|
||||
else:
|
||||
new_filename = f"backup_uploaded_{timestamp}_{original_filename}"
|
||||
|
||||
# Save file to backup directory
|
||||
file_path = backup_path / new_filename
|
||||
file.save(str(file_path))
|
||||
|
||||
# Get file size
|
||||
file_size = file_path.stat().st_size
|
||||
size_mb = round(file_size / (1024 * 1024), 2)
|
||||
|
||||
# Validate the uploaded file for integrity and compatibility
|
||||
validation_result = backup_manager.validate_backup_file(new_filename)
|
||||
|
||||
if not validation_result['success']:
|
||||
# Validation failed - remove the uploaded file
|
||||
file_path.unlink() # Delete the invalid file
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Validation failed: {validation_result["message"]}',
|
||||
'validation_details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}), 400
|
||||
|
||||
# Build response with validation details
|
||||
response = {
|
||||
'success': True,
|
||||
'message': 'Backup file uploaded and validated successfully',
|
||||
'filename': new_filename,
|
||||
'size': f'{size_mb} MB',
|
||||
'path': str(file_path),
|
||||
'validation': {
|
||||
'status': 'passed',
|
||||
'message': validation_result['message'],
|
||||
'details': validation_result.get('details', {}),
|
||||
'warnings': validation_result.get('warnings', [])
|
||||
}
|
||||
}
|
||||
|
||||
# Add warning flag if there are warnings
|
||||
if validation_result.get('warnings'):
|
||||
response['message'] = f'Backup uploaded with warnings: {"; ".join(validation_result["warnings"])}'
|
||||
|
||||
return jsonify(response)
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': f'Upload failed: {str(e)}'
|
||||
}), 500
|
||||
|
||||
Reference in New Issue
Block a user