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 .extensions import db def _safe_rollback() -> None: try: db.session.rollback() except Exception: pass def _wants_json_response() -> bool: if request.path.startswith("/api/"): return True best = request.accept_mimetypes.best_match(["application/json", "text/html"]) if not best: return False return ( best == "application/json" and request.accept_mimetypes["application/json"] >= request.accept_mimetypes["text/html"] ) def _get_status_phrase(status_code: int) -> str: try: return HTTPStatus(status_code).phrase except ValueError: return "Blad" def _get_status_description(status_code: int) -> str: try: return HTTPStatus(status_code).description except ValueError: return "Wystapil blad podczas przetwarzania zadania." def _error_headers(status_code: int) -> dict[str, str]: headers = {} if status_code >= 500: headers.update( { "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0, private", "Pragma": "no-cache", "Expires": "0", "Surrogate-Control": "no-store", } ) return headers def _render_error(status_code: int, message: str | None = None): phrase = _get_status_phrase(status_code) description = message or _get_status_description(status_code) headers = _error_headers(status_code) payload = { "status": status_code, "error": phrase, "message": description, } if _wants_json_response(): return jsonify(payload), status_code, headers try: return ( render_template( "error.html", error_code=status_code, error_name=phrase, error_message=description, ), status_code, headers, ) except TemplateNotFound: return ( f"{status_code} {phrase}: {description}", status_code, headers, ) 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_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_rollback() app.logger.exception("Nieobsluzony wyjatek: %s", exc) return _render_error(500, "Wystapil nieoczekiwany blad serwera.")