lnbits-legend/lnbits/exceptions.py

122 lines
4.2 KiB
Python
Raw Normal View History

import sys
import traceback
from http import HTTPStatus
from typing import Optional
from fastapi import FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse, RedirectResponse, Response
from loguru import logger
from .helpers import template_renderer
class PaymentError(Exception):
def __init__(self, message: str, status: str = "pending"):
self.message = message
self.status = status
class InvoiceError(Exception):
def __init__(self, message: str, status: str = "pending"):
self.message = message
self.status = status
def render_html_error(request: Request, exc: Exception) -> Optional[Response]:
# Only the browser sends "text/html" request
# not fail proof, but everything else get's a JSON response
2024-11-13 10:28:46 +02:00
if not request.headers:
return None
if "text/html" not in request.headers.get("accept", ""):
return None
if (
2024-11-13 10:28:46 +02:00
isinstance(exc, HTTPException)
and exc.headers
and "token-expired" in exc.headers
):
2024-11-13 10:28:46 +02:00
response = RedirectResponse("/")
response.delete_cookie("cookie_access_token")
response.delete_cookie("is_lnbits_user_authorized")
response.set_cookie("is_access_token_expired", "true")
return response
[feat] Pay to enable extension (#2516) * feat: add payment tab * feat: add buttons * feat: persist `pay to enable` changes * fix: do not disable extension on upgrade * fix: show releases tab first * feat: extract `enableExtension` logic * refactor: rename routes * feat: show dialog for paying extension * feat: create invoice to enable * refactor: extract enable/disable extension logic * feat: add extra info to UserExtensions * feat: check payment for extension enable * fix: parsing * feat: admins must not pay * fix: code checks * fix: test * refactor: extract extension activate/deactivate to the `api` side * feat: add `get_user_extensions ` * feat: return explicit `requiresPayment` * feat: add `isPaymentRequired` to extension list * fix: `paid_to_enable` status * fix: ui layout * feat: show QR Code * feat: wait for invoice to be paid * test: removed deprecated test and dead code * feat: add re-check button * refactor: rename paths for endpoints * feat: i18n * feat: add `{"success": True}` * test: fix listener * fix: rebase errors * chore: update bundle * fix: return error status code for the HTML error pages * fix: active extension loading from file system * chore: temp commit * fix: premature optimisation * chore: make check * refactor: remove extracted logic * chore: code format * fix: enable by default after install * fix: use `discard` instead of `remove` for `set` * chore: code format * fix: better error code * fix: check for stop function before invoking * feat: check if the wallet belongs to the admin user * refactor: return 402 Requires Payment * chore: more typing * chore: temp checkout different branch for tests * fix: too much typing * fix: remove try-except * fix: typo * fix: manual format * fix: merge issue * remove this line --------- Co-authored-by: dni ⚡ <office@dnilabs.com>
2024-05-28 14:07:33 +03:00
2024-11-13 10:28:46 +02:00
status_code: int = (
exc.status_code
if isinstance(exc, HTTPException)
else HTTPStatus.INTERNAL_SERVER_ERROR
)
2024-11-13 10:28:46 +02:00
return template_renderer().TemplateResponse(
request, "error.html", {"err": f"Error: {exc!s}"}, status_code
)
feat: parse nested pydantic models `fetchone` and `fetchall` + add shortcuts for insert_query and update_query into `Database` (#2714) * feat: add shortcuts for insert_query and update_query into `Database` example: await db.insert("table_name", base_model) * remove where from argument * chore: code clean-up * extension manager * lnbits-qrcode components * parse date from dict * refactor: make `settings` a fixture * chore: remove verbose key names * fix: time column * fix: cast balance to `int` * extension toggle vue3 * vue3 @input migration * fix: payment extra and payment hash * fix dynamic fields and ext db migration * remove shadow on cards in dark theme * screwed up and made more css pushes to this branch * attempt to make chip component in settings dynamic fields * dynamic chips * qrscanner * clean init admin settings * make get_user better * add dbversion model * remove update_payment_status/extra/details * traces for value and assertion errors * refactor services * add PaymentFiatAmount * return Payment on api endpoints * rename to get_user_from_account * refactor: just refactor (#2740) * rc5 * Fix db cache (#2741) * [refactor] split services.py (#2742) * refactor: spit `core.py` (#2743) * refactor: make QR more customizable * fix: print.html * fix: qrcode options * fix: white shadow on dark theme * fix: datetime wasnt parsed in dict_to_model * add timezone for conversion * only parse timestamp for sqlite, postgres does it * log internal payment success * fix: export wallet to phone QR * Adding a customisable border theme, like gradient (#2746) * fixed mobile scan btn * fix test websocket * fix get_payments tests * dict_to_model skip none values * preimage none instead of defaulting to 0000... * fixup test real invoice tests * fixed pheonixd for wss * fix nodemanager test settings * fix lnbits funding * only insert extension when they dont exist --------- Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com> Co-authored-by: Tiago Vasconcelos <talvasconcelos@gmail.com> Co-authored-by: Arc <ben@arc.wales> Co-authored-by: Arc <33088785+arcbtc@users.noreply.github.com>
2024-10-29 09:58:22 +01:00
def register_exception_handlers(app: FastAPI):
"""Register exception handlers for the FastAPI app"""
@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
etype, _, tb = sys.exc_info()
traceback.print_exception(etype, exc, tb)
logger.error(f"Exception: {exc!s}")
return render_html_error(request, exc) or JSONResponse(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
content={"detail": str(exc)},
)
feat: parse nested pydantic models `fetchone` and `fetchall` + add shortcuts for insert_query and update_query into `Database` (#2714) * feat: add shortcuts for insert_query and update_query into `Database` example: await db.insert("table_name", base_model) * remove where from argument * chore: code clean-up * extension manager * lnbits-qrcode components * parse date from dict * refactor: make `settings` a fixture * chore: remove verbose key names * fix: time column * fix: cast balance to `int` * extension toggle vue3 * vue3 @input migration * fix: payment extra and payment hash * fix dynamic fields and ext db migration * remove shadow on cards in dark theme * screwed up and made more css pushes to this branch * attempt to make chip component in settings dynamic fields * dynamic chips * qrscanner * clean init admin settings * make get_user better * add dbversion model * remove update_payment_status/extra/details * traces for value and assertion errors * refactor services * add PaymentFiatAmount * return Payment on api endpoints * rename to get_user_from_account * refactor: just refactor (#2740) * rc5 * Fix db cache (#2741) * [refactor] split services.py (#2742) * refactor: spit `core.py` (#2743) * refactor: make QR more customizable * fix: print.html * fix: qrcode options * fix: white shadow on dark theme * fix: datetime wasnt parsed in dict_to_model * add timezone for conversion * only parse timestamp for sqlite, postgres does it * log internal payment success * fix: export wallet to phone QR * Adding a customisable border theme, like gradient (#2746) * fixed mobile scan btn * fix test websocket * fix get_payments tests * dict_to_model skip none values * preimage none instead of defaulting to 0000... * fixup test real invoice tests * fixed pheonixd for wss * fix nodemanager test settings * fix lnbits funding * only insert extension when they dont exist --------- Co-authored-by: Vlad Stan <stan.v.vlad@gmail.com> Co-authored-by: Tiago Vasconcelos <talvasconcelos@gmail.com> Co-authored-by: Arc <ben@arc.wales> Co-authored-by: Arc <33088785+arcbtc@users.noreply.github.com>
2024-10-29 09:58:22 +01:00
@app.exception_handler(AssertionError)
async def assert_error_handler(request: Request, exc: AssertionError):
etype, _, tb = sys.exc_info()
traceback.print_exception(etype, exc, tb)
logger.warning(f"AssertionError: {exc!s}")
return render_html_error(request, exc) or JSONResponse(
status_code=HTTPStatus.BAD_REQUEST,
content={"detail": str(exc)},
)
@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
etype, _, tb = sys.exc_info()
traceback.print_exception(etype, exc, tb)
logger.warning(f"ValueError: {exc!s}")
return render_html_error(request, exc) or JSONResponse(
status_code=HTTPStatus.BAD_REQUEST,
content={"detail": str(exc)},
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request, exc: RequestValidationError
):
logger.error(f"RequestValidationError: {exc!s}")
return render_html_error(request, exc) or JSONResponse(
status_code=HTTPStatus.BAD_REQUEST,
content={"detail": str(exc)},
)
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
logger.error(f"HTTPException {exc.status_code}: {exc.detail}")
return render_html_error(request, exc) or JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail},
)
@app.exception_handler(PaymentError)
async def payment_error_handler(request: Request, exc: PaymentError):
logger.error(f"{exc.message}, {exc.status}")
return JSONResponse(
status_code=520,
content={"detail": exc.message, "status": exc.status},
)
@app.exception_handler(InvoiceError)
async def invoice_error_handler(request: Request, exc: InvoiceError):
logger.error(f"{exc.message}, Status: {exc.status}")
return JSONResponse(
status_code=520,
content={"detail": exc.message, "status": exc.status},
)