from html import escape from http import HTTPStatus from flask import jsonify, render_template, request from jinja2 import TemplateNotFound from sqlalchemy.exc import OperationalError from werkzeug.exceptions import HTTPException from .utils import safe_db_rollback JSON_MIMETYPES = ["application/json", "text/html"] def _wants_json_response() -> bool: if request.path.startswith("/api/"): return True if request.is_json: return True best = request.accept_mimetypes.best_match(JSON_MIMETYPES) if not best: return False return ( best == "application/json" and request.accept_mimetypes["application/json"] >= request.accept_mimetypes["text/html"] ) def _status_phrase(status_code: int) -> str: try: return HTTPStatus(status_code).phrase except ValueError: return "Blad" def _status_description(status_code: int) -> str: try: return HTTPStatus(status_code).description except ValueError: return "Wystapil blad podczas przetwarzania zadania." def _plain_fallback(status_code: int, phrase: str, description: str): html = f""" {status_code} {escape(phrase)}

{status_code} - {escape(phrase)}

{escape(description)}

""" return html, status_code def _render_error(status_code: int, message: str | None = None): phrase = _status_phrase(status_code) description = message or _status_description(status_code) payload = {"status": status_code, "error": phrase, "message": description} if _wants_json_response(): return jsonify(payload), status_code try: return ( render_template( "error.html", error_code=status_code, error_name=phrase, error_message=description, ), status_code, ) except TemplateNotFound: return _plain_fallback(status_code, phrase, description) except Exception: return _plain_fallback(status_code, phrase, description) def register_error_handlers(app): @app.errorhandler(HTTPException) def handle_http_exception(exc): return _render_error(exc.code or 500, exc.description) @app.errorhandler(OperationalError) def handle_operational_error(exc): safe_db_rollback() app.logger.exception("Blad polaczenia z baza danych: %s", exc) return _render_error(503, "Baza danych jest chwilowo niedostepna. Sprobuj ponownie za chwile.") @app.errorhandler(Exception) def handle_unexpected_error(exc): safe_db_rollback() app.logger.exception("Nieobsluzony wyjatek: %s", exc) return _render_error(500, "Wystapil nieoczekiwany blad serwera.")