mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 00:00:13 -08:00
feat: Implement comprehensive backup web application with Docker, systemd service, and Gunicorn support
This commit is contained in:
@@ -16,9 +16,8 @@ Author: Shell Repository
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
from flask import Flask, render_template, jsonify, request, send_file, abort
|
||||
from datetime import datetime
|
||||
from flask import Flask, render_template, jsonify, request, abort
|
||||
from werkzeug.utils import secure_filename
|
||||
import subprocess
|
||||
|
||||
@@ -48,10 +47,10 @@ def load_json_file(filepath):
|
||||
"""Safely load JSON file with error handling"""
|
||||
try:
|
||||
if os.path.exists(filepath):
|
||||
with open(filepath, 'r') as f:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading JSON file {filepath}: {e}")
|
||||
except (OSError, json.JSONDecodeError, UnicodeDecodeError) as e:
|
||||
logger.error("Error loading JSON file %s: %s", filepath, e)
|
||||
return None
|
||||
|
||||
|
||||
@@ -206,7 +205,6 @@ def index():
|
||||
"""Main dashboard"""
|
||||
try:
|
||||
# Get all services with their metrics
|
||||
service_names = get_services()
|
||||
services_data = []
|
||||
|
||||
# Status counters for summary
|
||||
@@ -259,8 +257,8 @@ def index():
|
||||
}
|
||||
|
||||
return render_template('dashboard.html', data=dashboard_data)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in index route: {e}")
|
||||
except (OSError, IOError, json.JSONDecodeError) as e:
|
||||
logger.error("Error in index route: %s", e)
|
||||
return f"Error: {e}", 500
|
||||
|
||||
|
||||
@@ -285,8 +283,9 @@ def api_service_details(service_name):
|
||||
'backup_files': backup_files,
|
||||
'log_files': log_files
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting service details for {service_name}: {e}")
|
||||
except (OSError, IOError, json.JSONDecodeError) as e:
|
||||
logger.error("Error getting service details for %s: %s",
|
||||
service_name, e)
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
|
||||
@@ -328,8 +327,8 @@ def service_detail(service_name):
|
||||
service_data['latest_backup'] = latest_backup['path']
|
||||
|
||||
return render_template('service.html', service=service_data)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in service detail for {service_name}: {e}")
|
||||
except (OSError, IOError, json.JSONDecodeError) as e:
|
||||
logger.error("Error in service detail for %s: %s", service_name, e)
|
||||
return f"Error: {e}", 500
|
||||
|
||||
|
||||
@@ -369,8 +368,8 @@ def logs_view():
|
||||
})
|
||||
|
||||
return render_template('logs.html', logs=formatted_logs, filter_service=service_filter)
|
||||
except Exception as e:
|
||||
logger.error(f"Error in logs view: {e}")
|
||||
except (OSError, IOError) as e:
|
||||
logger.error("Error in logs view: %s", e)
|
||||
return f"Error: {e}", 500
|
||||
|
||||
|
||||
@@ -408,7 +407,7 @@ def view_log(filename):
|
||||
# Read last N lines for large files
|
||||
max_lines = int(request.args.get('lines', 1000))
|
||||
|
||||
with open(log_path, 'r') as f:
|
||||
with open(log_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
if len(lines) > max_lines:
|
||||
lines = lines[-max_lines:]
|
||||
@@ -427,8 +426,8 @@ def view_log(filename):
|
||||
"%Y-%m-%d %H:%M:%S"),
|
||||
total_lines=len(lines),
|
||||
lines_shown=min(len(lines), max_lines))
|
||||
except Exception as e:
|
||||
logger.error(f"Error viewing log {filename}: {e}")
|
||||
except (OSError, IOError, UnicodeDecodeError, ValueError) as e:
|
||||
logger.error("Error viewing log %s: %s", filename, e)
|
||||
return f"Error: {e}", 500
|
||||
|
||||
|
||||
@@ -449,7 +448,8 @@ def api_refresh_metrics():
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=300 # 5 minute timeout
|
||||
timeout=300, # 5 minute timeout
|
||||
check=False
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
@@ -460,7 +460,7 @@ def api_refresh_metrics():
|
||||
'output': result.stdout
|
||||
})
|
||||
else:
|
||||
logger.error(f"Metrics refresh failed: {result.stderr}")
|
||||
logger.error("Metrics refresh failed: %s", result.stderr)
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': 'Metrics refresh failed',
|
||||
@@ -477,8 +477,8 @@ def api_refresh_metrics():
|
||||
'status': 'error',
|
||||
'message': 'Metrics refresh timed out'
|
||||
}), 408
|
||||
except Exception as e:
|
||||
logger.error(f"Error refreshing metrics: {e}")
|
||||
except (OSError, subprocess.SubprocessError) as e:
|
||||
logger.error("Error refreshing metrics: %s", e)
|
||||
return jsonify({
|
||||
'status': 'error',
|
||||
'message': str(e)
|
||||
@@ -498,14 +498,14 @@ def health_check():
|
||||
|
||||
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
def not_found(_error):
|
||||
return render_template('error.html',
|
||||
error_code=404,
|
||||
error_message="Page not found"), 404
|
||||
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_error(error):
|
||||
def internal_error(_error):
|
||||
return render_template('error.html',
|
||||
error_code=500,
|
||||
error_message="Internal server error"), 500
|
||||
|
||||
Reference in New Issue
Block a user