Coverage for app / helpers / globals.py: 92%
37 statements
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-06 04:49 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2025-12-06 04:49 +0000
1"""
2This module is used to register global error handlers, context processors, and variables
3for a Flask application. It ensures that custom error handling, utility functions, and
4global variables (like `current_user`) are available to all templates and views.
5"""
6import time
8from flask import jsonify, session, request
9from flask.sessions import NullSession
10from flask_login import current_user
12THIRTY_MINUTES_IN_SECONDS = 1800
15def register_globals(app):
16 """
17 Register global error handlers, context processors, and variables for a Flask app.
19 This function sets up custom error handlers, Jinja2 context processors, and global
20 variables to be made available throughout the lifecycle of a Flask request.
21 """
23 # Define the 403 error handler
24 @app.errorhandler(403)
25 def access_forbidden(e):
26 """
27 Handles 403 Forbidden errors by returning a JSON response with an error message.
29 :param e: The exception that triggered the error
30 :return: A JSON response object and a 403 HTTP status code
31 """
32 return jsonify({'error': f'You do not have permission to access this resource {e}'}), 403
34 # Register the global Jinja2 context processor
35 @app.context_processor
36 def utility_processor():
37 """
38 Provides utility functions to the Jinja2 template context.
40 Returns a dictionary of helper functions that can be accessed directly within templates.
41 """
42 from app.helpers.utilities import parse_url # pylint: disable=import-outside-toplevel
43 return {"parse_url": parse_url}
45 @app.before_request
46 def add_global_vars():
47 """
48 Adds global variables to the Jinja2 template environment before processing a request.
50 Makes information like the `current_user` available globally to all templates and macros.
51 """
52 # Access the global Jinja environment, including in macros
53 app.jinja_env.globals.update(current_user=current_user)
55 @app.before_request
56 def before_request():
57 """
58 Implement sliding sessions
59 """
60 if session and not isinstance(session, NullSession):
61 session.permanent = True # Use a permanent session with the configured timeout
62 session.modified = True # Update session timestamp on each request
64 @app.before_request
65 def check_session_timeout():
66 """
67 Implement activity timeout
68 """
69 if not session or isinstance(session, NullSession):
70 return
72 current_time = time.time()
73 if 'last_activity' in session:
74 # If inactive for more than 30 minutes, clear the session
75 if current_time - session['last_activity'] > THIRTY_MINUTES_IN_SECONDS: 75 ↛ 76line 75 didn't jump to line 76 because the condition on line 75 was never true
76 session.clear()
77 session['last_activity'] = current_time
79 @app.before_request
80 def check_ip_binding():
81 """
82 Bind session to an IP address
83 :return:
84 """
85 if not session or isinstance(session, NullSession):
86 return
88 if 'user_ip' in session and session['user_ip'] != request.remote_addr: 88 ↛ 90line 88 didn't jump to line 90 because the condition on line 88 was never true
89 # IP address has changed, potential session hijacking
90 session.clear()
91 session['user_ip'] = request.remote_addr