- error handling now uses a more comprehensive error communication system.
This commit is contained in:
22
common/templates/error/401.html
Normal file
22
common/templates/error/401.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Unauthorized</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
|
||||
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
p { margin: 0 0 16px; line-height:1.6; }
|
||||
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<h1>Not authorized</h1>
|
||||
<p>Your session may have expired or this action is not permitted.</p>
|
||||
<p><a class="btn" href="/">Go to home</a></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
22
common/templates/error/403.html
Normal file
22
common/templates/error/403.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Forbidden</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
|
||||
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
p { margin: 0 0 16px; line-height:1.6; }
|
||||
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<h1>Access forbidden</h1>
|
||||
<p>You don't have permission to access this resource.</p>
|
||||
<p><a class="btn" href="/">Go to home</a></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
22
common/templates/error/404.html
Normal file
22
common/templates/error/404.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Page not found</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
|
||||
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
p { margin: 0 0 16px; line-height:1.6; }
|
||||
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<h1>Page not found</h1>
|
||||
<p>The page you are looking for doesn’t exist or has been moved.</p>
|
||||
<p><a class="btn" href="/">Go to home</a></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
22
common/templates/error/500.html
Normal file
22
common/templates/error/500.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Something went wrong</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
|
||||
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
p { margin: 0 0 16px; line-height:1.6; }
|
||||
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<h1>We’re sorry — something went wrong</h1>
|
||||
<p>Please try again later. If the issue persists, contact support.</p>
|
||||
<p><a class="btn" href="/">Go to home</a></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
22
common/templates/error/generic.html
Normal file
22
common/templates/error/generic.html
Normal file
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Error</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background:#f7f7f9; color:#222; }
|
||||
.wrap { max-width: 720px; margin: 10vh auto; background:#fff; border:1px solid #e5e7eb; border-radius:12px; padding:32px; box-shadow: 0 8px 24px rgba(0,0,0,0.06); }
|
||||
h1 { margin: 0 0 8px; font-size: 28px; }
|
||||
p { margin: 0 0 16px; line-height:1.6; }
|
||||
a.btn { display:inline-block; padding:10px 16px; background:#2c3e50; color:#fff; text-decoration:none; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="wrap">
|
||||
<h1>Oops! Something went wrong</h1>
|
||||
<p>Please try again. If the issue persists, contact support.</p>
|
||||
<p><a class="btn" href="/">Go to home</a></p>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -10,41 +10,54 @@ from common.utils.nginx_utils import prefixed_url_for
|
||||
|
||||
|
||||
def not_found_error(error):
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
if profile == 'web_app':
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
current_app.logger.error(f"Not Found Error: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
return render_template('error/404.html'), 404
|
||||
|
||||
|
||||
def internal_server_error(error):
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
if profile == 'web_app':
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
current_app.logger.error(f"Internal Server Error: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
return render_template('error/500.html'), 500
|
||||
|
||||
|
||||
def not_authorised_error(error):
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
if profile == 'web_app':
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
current_app.logger.error(f"Not Authorised Error: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
return render_template('error/401.html')
|
||||
return render_template('error/401.html'), 401
|
||||
|
||||
|
||||
def access_forbidden(error):
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
if profile == 'web_app':
|
||||
if not current_user.is_authenticated:
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
current_app.logger.error(f"Access Forbidden: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
return render_template('error/403.html')
|
||||
return render_template('error/403.html'), 403
|
||||
|
||||
|
||||
def key_error_handler(error):
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
# Check if the KeyError is specifically for 'tenant'
|
||||
if str(error) == "'tenant'":
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
if profile == 'web_app':
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
else:
|
||||
current_app.logger.warning("Session tenant missing in chat_client context")
|
||||
return render_template('error/401.html'), 401
|
||||
# For other KeyErrors, you might want to log the error and return a generic error page
|
||||
current_app.logger.error(f"Key Error: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
@@ -79,19 +92,24 @@ def no_tenant_selected_error(error):
|
||||
"""Handle errors when no tenant is selected in the current session.
|
||||
|
||||
This typically happens when a session expires or becomes invalid after
|
||||
a long period of inactivity. The user will be redirected to the login page.
|
||||
a long period of inactivity. The user will be redirected to the login page (web_app)
|
||||
or shown an error page (chat_client).
|
||||
"""
|
||||
profile = current_app.config.get('ERRORS_PROFILE', 'web_app')
|
||||
current_app.logger.error(f"No Session Tenant Error: {error}")
|
||||
current_app.logger.error(traceback.format_exc())
|
||||
flash('Your session expired. You will have to re-enter your credentials', 'warning')
|
||||
|
||||
# Perform logout if user is authenticated
|
||||
if current_user.is_authenticated:
|
||||
from flask_security.utils import logout_user
|
||||
logout_user()
|
||||
|
||||
# Redirect to login page
|
||||
return redirect(prefixed_url_for('security.login'))
|
||||
if profile == 'web_app':
|
||||
# Perform logout if user is authenticated
|
||||
if current_user.is_authenticated:
|
||||
from flask_security.utils import logout_user
|
||||
logout_user()
|
||||
# Redirect to login page
|
||||
return redirect(prefixed_url_for('security.login', for_redirect=True))
|
||||
else:
|
||||
# chat_client: render 401 page
|
||||
return render_template('error/401.html'), 401
|
||||
|
||||
|
||||
def general_exception(e):
|
||||
@@ -122,7 +140,10 @@ def template_syntax_error(error):
|
||||
error_details=f"Error in template '{error.filename}' at line {error.lineno}: {error.message}"), 500
|
||||
|
||||
|
||||
def register_error_handlers(app):
|
||||
def register_error_handlers(app, profile: str = 'web_app'):
|
||||
# Store profile in app config to drive handler behavior
|
||||
app.config['ERRORS_PROFILE'] = profile
|
||||
|
||||
app.register_error_handler(404, not_found_error)
|
||||
app.register_error_handler(500, internal_server_error)
|
||||
app.register_error_handler(401, not_authorised_error)
|
||||
|
||||
Reference in New Issue
Block a user