Coverage for ckanext/udc/error_handler.py: 47%
55 statements
« prev ^ index » next coverage.py v7.7.1, created at 2026-01-19 23:48 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2026-01-19 23:48 +0000
1from __future__ import annotations
2from typing import Any, Callable, Collection, KeysView, Optional, Union, cast
4from ckanext.udc_react.constants import UDC_REACT_PATH
5from ckan.types import Schema, Context, CKANApp, Response
6from ckan.common import current_user, CKANConfig, _
7from werkzeug.exceptions import (
8 default_exceptions,
9 HTTPException,
10 Unauthorized,
11 Forbidden,
12)
13from typing import Any, Callable, Collection, KeysView, Optional, Union, cast
14import ckan.lib.base as base
15import sys
16import logging
17import chalk
18import ckan.lib.helpers as h
19import pprint
20from flask import session, request, Response, abort
22log = logging.getLogger(__name__)
25MESSAGE_NOT_LOGGED_IN_ADD_TO_CATALOGUE = _("""
26You are not authorized to add to the catalogue. Please login to add a catalogue entry. If you do not have an account, please <a href="/user/register">create one</a>.
27""")
28MESSAGE_NOT_LOGGED_IN_CREATE_ORGANIZATION = _("""
29You are not authorized to create an organization. Please login to create an organization. If you do not have an account, please <a href="/user/register">create one</a>.
30""")
32MESSAGE_NOT_LOGGED_IN_REQUEST_ORGANIZATION_ACCESS = _("""
33You are not authorized to request access to an organization. Please login to request access to an organization. If you do not have an account, please <a href="/user/register">create one</a>.
34""")
36MESSAGE_NOT_LOGGED_IN_WRONG_USER = _("""
37You are not authorized to access this page. Please login with the correct account.
38""")
40MESSAGE_NOT_LOGGED_IN_VIEW_ORGANIZATION_ACCESS_REQUESTS = _("""
41You are not authorized to view organization access requests. Please login to view organization access requests.
42""")
45def clear_and_flash(message, category):
46 # Remove the error flash message
47 if "_flashes" in session:
48 session["_flashes"].clear()
49 # Add a custom error message and type to the redirect
50 h.flash(message, category)
53def override_error_handler(app: CKANApp, config: CKANConfig):
55 @app.before_request
56 def display_flashes():
57 if request.full_path.endswith(f"came_from=/{UDC_REACT_PATH}/request-organization-access"):
58 clear_and_flash(MESSAGE_NOT_LOGGED_IN_REQUEST_ORGANIZATION_ACCESS, "alert-warning")
59 elif f"came_from=/{UDC_REACT_PATH}/request-organization-access/token/" in request.full_path:
60 clear_and_flash(MESSAGE_NOT_LOGGED_IN_VIEW_ORGANIZATION_ACCESS_REQUESTS, "alert-warning")
62 @app.errorhandler(Forbidden)
63 def handle_forbidden(e) -> Union[tuple[str, Optional[int]], Optional[Response]]:
64 log.info(chalk.red(str(e)))
65 log.info(pprint.pformat(e.__dict__))
67 # Custom error handler for dataset creation "Unauthorized to create a package"
68 if e.description == "Unauthorized to create a package":
69 if current_user.is_anonymous:
70 clear_and_flash(MESSAGE_NOT_LOGGED_IN_ADD_TO_CATALOGUE, "alert-warning")
71 return h.redirect_to(
72 controller="user", action="login", next="/catalogue/new"
73 )
74 else:
75 # Remove the error flash message
76 session["_flashes"].clear()
77 # Show a custom error message and redirect to the organization access request page
78 return h.redirect_to(f"/{UDC_REACT_PATH}/request-organization-access/redirected")
80 elif e.description == "Unauthorized to create a group":
81 clear_and_flash(MESSAGE_NOT_LOGGED_IN_CREATE_ORGANIZATION, "alert-warning")
82 return h.redirect_to(
83 controller="user", action="login", next="/organization/new"
84 )
86 # Default CKAN error handler below
87 debug = config.get("debug")
88 if isinstance(e, HTTPException):
89 if debug:
90 log.debug(e, exc_info=sys.exc_info) # type: ignore
91 else:
92 log.info(e)
94 show_login_redirect_link = current_user.is_anonymous and type(e) in (
95 Unauthorized,
96 Forbidden,
97 )
98 extra_vars = {
99 "code": e.code,
100 "content": e.description,
101 "name": e.name,
102 "show_login_redirect_link": show_login_redirect_link,
103 }
104 return base.render("error_document_template.html", extra_vars), e.code
106 log.error(e, exc_info=sys.exc_info) # type: ignore
107 extra_vars = {"code": [500], "content": "Internal server error"}
108 return base.render("error_document_template.html", extra_vars), 500