lnbits-legend/lnbits/extensions/lnurlp/views_api.py
2023-01-10 09:45:12 +02:00

169 lines
5.0 KiB
Python

import json
from http import HTTPStatus
from fastapi import Depends, Query, Request
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type
from lnbits.utils.exchange_rates import currencies, get_fiat_rate_satoshis
from . import lnurlp_ext
from .crud import (
create_pay_link,
delete_pay_link,
get_pay_link,
get_pay_links,
update_pay_link,
)
from .models import CreatePayLinkData
@lnurlp_ext.get("/api/v1/currencies")
async def api_list_currencies_available():
return list(currencies.keys())
@lnurlp_ext.get("/api/v1/links", status_code=HTTPStatus.OK)
async def api_links(
req: Request,
wallet: WalletTypeInfo = Depends(get_key_type),
all_wallets: bool = Query(False),
):
wallet_ids = [wallet.wallet.id]
if all_wallets:
user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
try:
return [
{**link.dict(), "lnurl": link.lnurl(req)}
for link in await get_pay_links(wallet_ids)
]
except LnurlInvalidUrl:
raise HTTPException(
status_code=HTTPStatus.UPGRADE_REQUIRED,
detail="LNURLs need to be delivered over a publically accessible `https` domain or Tor.",
)
@lnurlp_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
async def api_link_retrieve(
r: Request, link_id, wallet: WalletTypeInfo = Depends(get_key_type)
):
link = await get_pay_link(link_id)
if not link:
raise HTTPException(
detail="Pay link does not exist.", status_code=HTTPStatus.NOT_FOUND
)
if link.wallet != wallet.wallet.id:
raise HTTPException(
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
)
return {**link.dict(), **{"lnurl": link.lnurl(r)}}
@lnurlp_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)
@lnurlp_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
async def api_link_create_or_update(
data: CreatePayLinkData,
request: Request,
link_id=None,
wallet: WalletTypeInfo = Depends(get_key_type),
):
if data.min > data.max:
raise HTTPException(
detail="Min is greater than max.", status_code=HTTPStatus.BAD_REQUEST
)
if data.currency == None and (
round(data.min) != data.min or round(data.max) != data.max or data.min < 1
):
raise HTTPException(
detail="Must use full satoshis.", status_code=HTTPStatus.BAD_REQUEST
)
if data.webhook_headers:
try:
json.loads(data.webhook_headers)
except ValueError:
raise HTTPException(
detail="Invalid JSON in webhook_headers.",
status_code=HTTPStatus.BAD_REQUEST,
)
if data.webhook_body:
try:
json.loads(data.webhook_body)
except ValueError:
raise HTTPException(
detail="Invalid JSON in webhook_body.",
status_code=HTTPStatus.BAD_REQUEST,
)
# database only allows int4 entries for min and max. For fiat currencies,
# we multiply by data.fiat_base_multiplier (usually 100) to save the value in cents.
if data.currency and data.fiat_base_multiplier:
data.min *= data.fiat_base_multiplier
data.max *= data.fiat_base_multiplier
if data.success_url is not None and not data.success_url.startswith("https://"):
raise HTTPException(
detail="Success URL must be secure https://...",
status_code=HTTPStatus.BAD_REQUEST,
)
if link_id:
link = await get_pay_link(link_id)
if not link:
raise HTTPException(
detail="Pay link does not exist.", status_code=HTTPStatus.NOT_FOUND
)
if link.wallet != wallet.wallet.id:
raise HTTPException(
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
)
link = await update_pay_link(**data.dict(), link_id=link_id)
else:
link = await create_pay_link(data, wallet_id=wallet.wallet.id)
assert link
return {**link.dict(), "lnurl": link.lnurl(request)}
@lnurlp_ext.delete("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
async def api_link_delete(link_id, wallet: WalletTypeInfo = Depends(get_key_type)):
link = await get_pay_link(link_id)
if not link:
raise HTTPException(
detail="Pay link does not exist.", status_code=HTTPStatus.NOT_FOUND
)
if link.wallet != wallet.wallet.id:
raise HTTPException(
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
)
await delete_pay_link(link_id)
return {"success": True}
@lnurlp_ext.get("/api/v1/rate/{currency}", status_code=HTTPStatus.OK)
async def api_check_fiat_rate(currency):
try:
rate = await get_fiat_rate_satoshis(currency)
except AssertionError:
rate = None
return {"rate": rate}