mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-11-09 13:35:12 +09:00
Backend: accept and persist an 'enabled' flag when updating monitoring config; add slug normalization and validation in StatusPageService to enforce lowercase alphanumeric-hyphen slugs. Frontend: add PublicStatusPage component and route (/status/:slug). Major overhaul of Monitoring.jsx: introduce defaults for thresholds, improved state handling (loading/saving/checking flags), reworked UI and tabs (Alert Rules, Delivery, History), add Check Now, Refresh, toasts, and Switch UI for enabling checks; persist and validate thresholds on save. App.jsx imports the public page and registers the route. StatusPages.jsx refactor: slug normalization, autosync slug from name, improved page/component/incident flows (create, load, run checks, copy public URL, delete handling), UI/ux improvements and additional metadata. Overall implements better validation, UX, and public status page support.
184 lines
5.4 KiB
Python
184 lines
5.4 KiB
Python
from flask import Blueprint, request, jsonify
|
|
from flask_jwt_extended import jwt_required, get_jwt_identity
|
|
from app.models import User
|
|
from app.services.monitoring_service import MonitoringService
|
|
|
|
monitoring_bp = Blueprint('monitoring', __name__)
|
|
|
|
|
|
def admin_required(fn):
|
|
"""Decorator to require admin role."""
|
|
from functools import wraps
|
|
|
|
@wraps(fn)
|
|
def wrapper(*args, **kwargs):
|
|
current_user_id = get_jwt_identity()
|
|
user = User.query.get(current_user_id)
|
|
if not user or user.role != 'admin':
|
|
return jsonify({'error': 'Admin access required'}), 403
|
|
return fn(*args, **kwargs)
|
|
return wrapper
|
|
|
|
|
|
@monitoring_bp.route('/status', methods=['GET'])
|
|
@jwt_required()
|
|
def get_status():
|
|
"""Get monitoring status and current metrics."""
|
|
status = MonitoringService.get_status()
|
|
return jsonify(status), 200
|
|
|
|
|
|
@monitoring_bp.route('/metrics', methods=['GET'])
|
|
@jwt_required()
|
|
def get_metrics():
|
|
"""Get current system metrics."""
|
|
metrics = MonitoringService.get_current_metrics()
|
|
return jsonify(metrics), 200
|
|
|
|
|
|
@monitoring_bp.route('/alerts/check', methods=['GET'])
|
|
@jwt_required()
|
|
def check_alerts():
|
|
"""Check current threshold violations."""
|
|
alerts = MonitoringService.check_thresholds()
|
|
return jsonify({'alerts': alerts}), 200
|
|
|
|
|
|
@monitoring_bp.route('/alerts/history', methods=['GET'])
|
|
@jwt_required()
|
|
def get_alert_history():
|
|
"""Get alert history."""
|
|
limit = request.args.get('limit', 100, type=int)
|
|
alerts = MonitoringService.get_alert_history(limit)
|
|
return jsonify({'alerts': alerts}), 200
|
|
|
|
|
|
@monitoring_bp.route('/alerts/history', methods=['DELETE'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def clear_alert_history():
|
|
"""Clear alert history."""
|
|
result = MonitoringService.clear_alert_history()
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/config', methods=['GET'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def get_config():
|
|
"""Get monitoring configuration."""
|
|
config = MonitoringService.get_config()
|
|
# Don't expose sensitive data
|
|
if 'email' in config and 'smtp_password' in config['email']:
|
|
config['email']['smtp_password'] = '***' if config['email']['smtp_password'] else ''
|
|
return jsonify(config), 200
|
|
|
|
|
|
@monitoring_bp.route('/config', methods=['PUT'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def update_config():
|
|
"""Update monitoring configuration."""
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'error': 'No data provided'}), 400
|
|
|
|
current_config = MonitoringService.get_config()
|
|
|
|
# Update config with new values
|
|
if 'enabled' in data:
|
|
current_config['enabled'] = bool(data['enabled'])
|
|
|
|
if 'thresholds' in data:
|
|
current_config['thresholds'] = {**current_config.get('thresholds', {}), **data['thresholds']}
|
|
|
|
if 'check_interval' in data:
|
|
current_config['check_interval'] = data['check_interval']
|
|
|
|
if 'email' in data:
|
|
email_config = current_config.get('email', {})
|
|
new_email = data['email']
|
|
|
|
# Preserve password if not provided or masked
|
|
if new_email.get('smtp_password') in [None, '', '***']:
|
|
new_email['smtp_password'] = email_config.get('smtp_password', '')
|
|
|
|
current_config['email'] = {**email_config, **new_email}
|
|
|
|
if 'webhook' in data:
|
|
current_config['webhook'] = {**current_config.get('webhook', {}), **data['webhook']}
|
|
|
|
result = MonitoringService.save_config(current_config)
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/thresholds', methods=['GET'])
|
|
@jwt_required()
|
|
def get_thresholds():
|
|
"""Get alert thresholds."""
|
|
thresholds = MonitoringService.get_thresholds()
|
|
return jsonify({'thresholds': thresholds}), 200
|
|
|
|
|
|
@monitoring_bp.route('/thresholds', methods=['PUT'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def update_thresholds():
|
|
"""Update alert thresholds."""
|
|
data = request.get_json()
|
|
if not data:
|
|
return jsonify({'error': 'No data provided'}), 400
|
|
|
|
result = MonitoringService.set_thresholds(data)
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/start', methods=['POST'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def start_monitoring():
|
|
"""Start background monitoring."""
|
|
result = MonitoringService.start_monitoring()
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/stop', methods=['POST'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def stop_monitoring():
|
|
"""Stop background monitoring."""
|
|
result = MonitoringService.stop_monitoring()
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/test/email', methods=['POST'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def test_email_alert():
|
|
"""Send a test email alert."""
|
|
test_alerts = [{
|
|
'type': 'test',
|
|
'severity': 'info',
|
|
'message': 'This is a test alert from ServerKit',
|
|
'value': 0,
|
|
'threshold': 0
|
|
}]
|
|
result = MonitoringService.send_email_alert(test_alerts)
|
|
return jsonify(result), 200 if result['success'] else 400
|
|
|
|
|
|
@monitoring_bp.route('/test/webhook', methods=['POST'])
|
|
@jwt_required()
|
|
@admin_required
|
|
def test_webhook_alert():
|
|
"""Send a test webhook alert."""
|
|
test_alerts = [{
|
|
'type': 'test',
|
|
'severity': 'info',
|
|
'message': 'This is a test alert from ServerKit',
|
|
'value': 0,
|
|
'threshold': 0
|
|
}]
|
|
result = MonitoringService.send_webhook_alert(test_alerts)
|
|
return jsonify(result), 200 if result['success'] else 400
|