mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-26 07:31:22 +01:00
* 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>
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
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 lnbits.core.services import InvoiceError, PaymentError
|
|
|
|
from .helpers import template_renderer
|
|
|
|
|
|
def register_exception_handlers(app: FastAPI):
|
|
register_exception_handler(app)
|
|
register_request_validation_exception_handler(app)
|
|
register_http_exception_handler(app)
|
|
register_payment_error_handler(app)
|
|
register_invoice_error_handler(app)
|
|
|
|
|
|
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
|
|
if (
|
|
request.headers
|
|
and "accept" in request.headers
|
|
and "text/html" in request.headers["accept"]
|
|
):
|
|
if (
|
|
isinstance(exc, HTTPException)
|
|
and exc.headers
|
|
and "token-expired" in exc.headers
|
|
):
|
|
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
|
|
|
|
status_code: int = (
|
|
exc.status_code
|
|
if isinstance(exc, HTTPException)
|
|
else HTTPStatus.INTERNAL_SERVER_ERROR
|
|
)
|
|
|
|
return template_renderer().TemplateResponse(
|
|
request, "error.html", {"err": f"Error: {exc!s}"}, status_code
|
|
)
|
|
|
|
return None
|
|
|
|
|
|
def register_exception_handler(app: FastAPI):
|
|
@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)},
|
|
)
|
|
|
|
|
|
def register_request_validation_exception_handler(app: FastAPI):
|
|
@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)},
|
|
)
|
|
|
|
|
|
def register_http_exception_handler(app: FastAPI):
|
|
@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},
|
|
)
|
|
|
|
|
|
def register_payment_error_handler(app: FastAPI):
|
|
@app.exception_handler(PaymentError)
|
|
async def payment_error_handler(request: Request, exc: PaymentError):
|
|
logger.error(f"PaymentError: {exc.message}, {exc.status}")
|
|
return JSONResponse(
|
|
status_code=520,
|
|
content={"detail": exc.message, "status": exc.status},
|
|
)
|
|
|
|
|
|
def register_invoice_error_handler(app: FastAPI):
|
|
@app.exception_handler(InvoiceError)
|
|
async def invoice_error_handler(request: Request, exc: InvoiceError):
|
|
logger.error(f"InvoiceError: {exc.message}, Status: {exc.status}")
|
|
return JSONResponse(
|
|
status_code=520,
|
|
content={"detail": exc.message, "status": exc.status},
|
|
)
|