Files
TimeTracker/app/utils/error_handlers.py
Dries Peeters 8322c73ddc Update tests
2025-11-05 13:58:38 +01:00

155 lines
5.9 KiB
Python

from flask import render_template, request, jsonify
from werkzeug.exceptions import HTTPException
import traceback
def get_user_friendly_message(status_code, error_description=None):
"""Get user-friendly error messages"""
messages = {
400: {
'title': 'Invalid Request',
'message': 'The request was invalid. Please check your input and try again.',
'recovery': ['Go to Dashboard', 'Go Back']
},
401: {
'title': 'Authentication Required',
'message': 'You need to log in to access this feature.',
'recovery': ['Go to Login']
},
403: {
'title': 'Access Denied',
'message': 'You don\'t have permission to perform this action.',
'recovery': ['Go to Dashboard', 'Go Back']
},
404: {
'title': 'Page Not Found',
'message': 'The page or resource you\'re looking for was not found.',
'recovery': ['Go to Dashboard', 'Go Back']
},
409: {
'title': 'Conflict',
'message': 'This action conflicts with existing data. Please refresh and try again.',
'recovery': ['Refresh Page', 'Go Back']
},
422: {
'title': 'Validation Error',
'message': 'Please check your input and try again.',
'recovery': ['Go Back']
},
429: {
'title': 'Too Many Requests',
'message': 'You\'ve made too many requests. Please wait a moment and try again.',
'recovery': ['Refresh Page']
},
500: {
'title': 'Server Error',
'message': 'A server error occurred. Our team has been notified. Please try again later.',
'recovery': ['Refresh Page', 'Go to Dashboard']
},
502: {
'title': 'Service Unavailable',
'message': 'The server is temporarily unavailable. Please try again later.',
'recovery': ['Refresh Page']
},
503: {
'title': 'Service Unavailable',
'message': 'Service temporarily unavailable. Please try again in a few moments.',
'recovery': ['Refresh Page']
},
504: {
'title': 'Request Timeout',
'message': 'The request took too long. Please try again.',
'recovery': ['Refresh Page', 'Go Back']
}
}
if status_code in messages:
msg = messages[status_code].copy()
if error_description:
msg['message'] = f"{msg['message']} ({error_description})"
return msg
return {
'title': 'Error',
'message': error_description or 'An error occurred. Please try again.',
'recovery': ['Go to Dashboard', 'Go Back']
}
def register_error_handlers(app):
"""Register error handlers for the application"""
@app.errorhandler(404)
def not_found_error(error):
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(404)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), 404
error_info = get_user_friendly_message(404)
return render_template('errors/404.html', error_info=error_info), 404
@app.errorhandler(500)
def internal_error(error):
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(500)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), 500
error_info = get_user_friendly_message(500)
return render_template('errors/500.html', error_info=error_info), 500
@app.errorhandler(403)
def forbidden_error(error):
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(403)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), 403
error_info = get_user_friendly_message(403)
return render_template('errors/403.html', error_info=error_info), 403
@app.errorhandler(400)
def bad_request_error(error):
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(400)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), 400
error_info = get_user_friendly_message(400)
return render_template('errors/400.html', error_info=error_info), 400
@app.errorhandler(HTTPException)
def handle_http_exception(error):
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(error.code, error.description)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), error.code
error_info = get_user_friendly_message(error.code, error.description)
return render_template('errors/generic.html', error=error, error_info=error_info), error.code
@app.errorhandler(Exception)
def handle_exception(error):
# Log the error
app.logger.error(f'Unhandled exception: {error}')
app.logger.error(traceback.format_exc())
if request.path.startswith('/api/'):
error_info = get_user_friendly_message(500)
return jsonify({
'error': error_info['message'],
'title': error_info['title'],
'recovery': error_info['recovery']
}), 500
error_info = get_user_friendly_message(500)
return render_template('errors/500.html', error_info=error_info), 500