feat: update to lnbits 1.0.0
This commit is contained in:
parent
242dd03961
commit
fe6cbe4e2d
8 changed files with 898 additions and 862 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "Pay Links",
|
"name": "Pay Links",
|
||||||
"short_description": "Make reusable LNURL pay links",
|
"short_description": "Make reusable LNURL pay links",
|
||||||
"tile": "/lnurlp/static/image/lnurl-pay.png",
|
"tile": "/lnurlp/static/image/lnurl-pay.png",
|
||||||
"min_lnbits_version": "0.12.4",
|
"min_lnbits_version": "1.0.0",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
"name": "arcbtc",
|
"name": "arcbtc",
|
||||||
|
|
|
||||||
117
crud.py
117
crud.py
|
|
@ -15,16 +15,14 @@ async def get_or_create_lnurlp_settings() -> LnurlpSettings:
|
||||||
return LnurlpSettings(**row)
|
return LnurlpSettings(**row)
|
||||||
else:
|
else:
|
||||||
settings = LnurlpSettings(nostr_private_key=PrivateKey().hex())
|
settings = LnurlpSettings(nostr_private_key=PrivateKey().hex())
|
||||||
await db.execute(
|
await db.execute(insert_query("lnurlp.settings", settings), settings.dict())
|
||||||
insert_query("lnurlp.settings", settings), (*settings.dict().values(),)
|
|
||||||
)
|
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
||||||
async def update_lnurlp_settings(settings: LnurlpSettings) -> LnurlpSettings:
|
async def update_lnurlp_settings(settings: LnurlpSettings) -> LnurlpSettings:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
update_query("lnurlp.settings", settings, where=""),
|
update_query("lnurlp.settings", settings, where=""),
|
||||||
(*settings.dict().values(),),
|
settings.dict(),
|
||||||
)
|
)
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
|
|
@ -35,109 +33,76 @@ async def delete_lnurlp_settings() -> None:
|
||||||
|
|
||||||
async def get_pay_link_by_username(username: str) -> Optional[PayLink]:
|
async def get_pay_link_by_username(username: str) -> Optional[PayLink]:
|
||||||
row = await db.fetchone(
|
row = await db.fetchone(
|
||||||
"SELECT * FROM lnurlp.pay_links WHERE username = ?", (username,)
|
"SELECT * FROM lnurlp.pay_links WHERE username = :username",
|
||||||
|
{"username": username},
|
||||||
)
|
)
|
||||||
return PayLink.from_row(row) if row else None
|
return PayLink(**row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def create_pay_link(data: CreatePayLinkData) -> PayLink:
|
async def create_pay_link(data: CreatePayLinkData) -> PayLink:
|
||||||
|
|
||||||
link_id = urlsafe_short_hash()[:6]
|
link_id = urlsafe_short_hash()[:6]
|
||||||
|
|
||||||
result = await db.execute(
|
assert data.wallet, "Wallet is required"
|
||||||
"""
|
|
||||||
INSERT INTO lnurlp.pay_links (
|
|
||||||
id,
|
|
||||||
wallet,
|
|
||||||
description,
|
|
||||||
min,
|
|
||||||
max,
|
|
||||||
served_meta,
|
|
||||||
served_pr,
|
|
||||||
webhook_url,
|
|
||||||
webhook_headers,
|
|
||||||
webhook_body,
|
|
||||||
success_text,
|
|
||||||
success_url,
|
|
||||||
comment_chars,
|
|
||||||
currency,
|
|
||||||
fiat_base_multiplier,
|
|
||||||
username,
|
|
||||||
zaps
|
|
||||||
|
|
||||||
|
link = PayLink(
|
||||||
|
id=link_id,
|
||||||
|
wallet=data.wallet,
|
||||||
|
description=data.description,
|
||||||
|
min=data.min,
|
||||||
|
max=data.max,
|
||||||
|
served_meta=0,
|
||||||
|
served_pr=0,
|
||||||
|
username=data.username,
|
||||||
|
zaps=data.zaps,
|
||||||
|
domain=None,
|
||||||
|
webhook_url=data.webhook_url,
|
||||||
|
webhook_headers=data.webhook_headers,
|
||||||
|
webhook_body=data.webhook_body,
|
||||||
|
success_text=data.success_text,
|
||||||
|
success_url=data.success_url,
|
||||||
|
currency=data.currency,
|
||||||
|
comment_chars=data.comment_chars,
|
||||||
|
fiat_base_multiplier=data.fiat_base_multiplier,
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
||||||
""",
|
|
||||||
(
|
|
||||||
link_id,
|
|
||||||
data.wallet,
|
|
||||||
data.description,
|
|
||||||
data.min,
|
|
||||||
data.max,
|
|
||||||
data.webhook_url,
|
|
||||||
data.webhook_headers,
|
|
||||||
data.webhook_body,
|
|
||||||
data.success_text,
|
|
||||||
data.success_url,
|
|
||||||
data.comment_chars,
|
|
||||||
data.currency,
|
|
||||||
data.fiat_base_multiplier,
|
|
||||||
data.username,
|
|
||||||
data.zaps,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
assert result
|
|
||||||
|
|
||||||
link = await get_pay_link(link_id)
|
await db.execute(insert_query("lnurlp.pay_links", link), link.dict())
|
||||||
assert link, "Newly created link couldn't be retrieved"
|
|
||||||
return link
|
return link
|
||||||
|
|
||||||
|
|
||||||
async def get_address_data(username: str) -> Optional[PayLink]:
|
async def get_address_data(username: str) -> Optional[PayLink]:
|
||||||
row = await db.fetchone(
|
row = await db.fetchone(
|
||||||
"SELECT * FROM lnurlp.pay_links WHERE username = ?", (username,)
|
"SELECT * FROM lnurlp.pay_links WHERE username = :username",
|
||||||
|
{"username": username},
|
||||||
)
|
)
|
||||||
return PayLink.from_row(row) if row else None
|
return PayLink(**row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_pay_link(link_id: str) -> Optional[PayLink]:
|
async def get_pay_link(link_id: str) -> Optional[PayLink]:
|
||||||
row = await db.fetchone("SELECT * FROM lnurlp.pay_links WHERE id = ?", (link_id,))
|
row = await db.fetchone(
|
||||||
return PayLink.from_row(row) if row else None
|
"SELECT * FROM lnurlp.pay_links WHERE id = :id", {"id": link_id}
|
||||||
|
)
|
||||||
|
return PayLink(**row) if row else None
|
||||||
|
|
||||||
|
|
||||||
async def get_pay_links(wallet_ids: Union[str, List[str]]) -> List[PayLink]:
|
async def get_pay_links(wallet_ids: Union[str, List[str]]) -> List[PayLink]:
|
||||||
if isinstance(wallet_ids, str):
|
if isinstance(wallet_ids, str):
|
||||||
wallet_ids = [wallet_ids]
|
wallet_ids = [wallet_ids]
|
||||||
|
|
||||||
q = ",".join(["?"] * len(wallet_ids))
|
q = ",".join([f"'{wallet_id}'" for wallet_id in wallet_ids])
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
f"""
|
f"SELECT * FROM lnurlp.pay_links WHERE wallet IN ({q}) ORDER BY Id"
|
||||||
SELECT * FROM lnurlp.pay_links WHERE wallet IN ({q})
|
|
||||||
ORDER BY Id
|
|
||||||
""",
|
|
||||||
(*wallet_ids,),
|
|
||||||
)
|
)
|
||||||
return [PayLink.from_row(row) for row in rows]
|
return [PayLink(**row) for row in rows]
|
||||||
|
|
||||||
|
|
||||||
async def update_pay_link(link_id: str, **kwargs) -> Optional[PayLink]:
|
async def update_pay_link(link: PayLink) -> PayLink:
|
||||||
|
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
|
||||||
await db.execute(
|
await db.execute(
|
||||||
f"UPDATE lnurlp.pay_links SET {q} WHERE id = ?", (*kwargs.values(), link_id)
|
update_query("lnurlp.pay_links", link),
|
||||||
|
link.dict(),
|
||||||
)
|
)
|
||||||
row = await db.fetchone("SELECT * FROM lnurlp.pay_links WHERE id = ?", (link_id,))
|
return link
|
||||||
return PayLink.from_row(row) if row else None
|
|
||||||
|
|
||||||
|
|
||||||
async def increment_pay_link(link_id: str, **kwargs) -> Optional[PayLink]:
|
|
||||||
q = ", ".join([f"{field[0]} = {field[0]} + ?" for field in kwargs.items()])
|
|
||||||
await db.execute(
|
|
||||||
f"UPDATE lnurlp.pay_links SET {q} WHERE id = ?", (*kwargs.values(), link_id)
|
|
||||||
)
|
|
||||||
row = await db.fetchone("SELECT * FROM lnurlp.pay_links WHERE id = ?", (link_id,))
|
|
||||||
return PayLink.from_row(row) if row else None
|
|
||||||
|
|
||||||
|
|
||||||
async def delete_pay_link(link_id: str) -> None:
|
async def delete_pay_link(link_id: str) -> None:
|
||||||
await db.execute("DELETE FROM lnurlp.pay_links WHERE id = ?", (link_id,))
|
await db.execute("DELETE FROM lnurlp.pay_links WHERE id = :id", {"id": link_id})
|
||||||
|
|
|
||||||
12
models.py
12
models.py
|
|
@ -1,9 +1,7 @@
|
||||||
import json
|
import json
|
||||||
from sqlite3 import Row
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Query, Request
|
||||||
from fastapi.param_functions import Query
|
|
||||||
from lnurl import encode as lnurl_encode
|
from lnurl import encode as lnurl_encode
|
||||||
from lnurl.types import LnurlPayMetadata
|
from lnurl.types import LnurlPayMetadata
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -61,14 +59,6 @@ class PayLink(BaseModel):
|
||||||
max: float
|
max: float
|
||||||
fiat_base_multiplier: int
|
fiat_base_multiplier: int
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_row(cls, row: Row) -> "PayLink":
|
|
||||||
data = dict(row)
|
|
||||||
if data["currency"] and data["fiat_base_multiplier"]:
|
|
||||||
data["min"] /= data["fiat_base_multiplier"]
|
|
||||||
data["max"] /= data["fiat_base_multiplier"]
|
|
||||||
return cls(**data)
|
|
||||||
|
|
||||||
def lnurl(self, req: Request) -> str:
|
def lnurl(self, req: Request) -> str:
|
||||||
url = req.url_for("lnurlp.api_lnurl_response", link_id=self.id)
|
url = req.url_for("lnurlp.api_lnurl_response", link_id=self.id)
|
||||||
url_str = str(url)
|
url_str = str(url)
|
||||||
|
|
|
||||||
1588
poetry.lock
generated
1588
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,7 @@ authors = ["Alan Bits <alan@lnbits.com>"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10 | ^3.9"
|
python = "^3.10 | ^3.9"
|
||||||
lnbits = "*"
|
lnbits = {version = "*", allow-prereleases = true}
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^24.3.0"
|
black = "^24.3.0"
|
||||||
|
|
|
||||||
4
views.py
4
views.py
|
|
@ -1,7 +1,6 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request
|
||||||
from fastapi.templating import Jinja2Templates
|
|
||||||
from lnbits.core.models import User
|
from lnbits.core.models import User
|
||||||
from lnbits.decorators import check_user_exists
|
from lnbits.decorators import check_user_exists
|
||||||
from lnbits.helpers import template_renderer
|
from lnbits.helpers import template_renderer
|
||||||
|
|
@ -17,9 +16,6 @@ def lnurlp_renderer():
|
||||||
return template_renderer(["lnurlp/templates"])
|
return template_renderer(["lnurlp/templates"])
|
||||||
|
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
|
||||||
|
|
||||||
|
|
||||||
@lnurlp_generic_router.get("/", response_class=HTMLResponse)
|
@lnurlp_generic_router.get("/", response_class=HTMLResponse)
|
||||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return lnurlp_renderer().TemplateResponse(
|
return lnurlp_renderer().TemplateResponse(
|
||||||
|
|
|
||||||
20
views_api.py
20
views_api.py
|
|
@ -8,7 +8,6 @@ from lnbits.core.crud import get_user, get_wallet
|
||||||
from lnbits.core.models import WalletTypeInfo
|
from lnbits.core.models import WalletTypeInfo
|
||||||
from lnbits.decorators import (
|
from lnbits.decorators import (
|
||||||
check_admin,
|
check_admin,
|
||||||
get_key_type,
|
|
||||||
require_admin_key,
|
require_admin_key,
|
||||||
require_invoice_key,
|
require_invoice_key,
|
||||||
)
|
)
|
||||||
|
|
@ -41,13 +40,13 @@ async def api_list_currencies_available():
|
||||||
@lnurlp_api_router.get("/api/v1/links", status_code=HTTPStatus.OK)
|
@lnurlp_api_router.get("/api/v1/links", status_code=HTTPStatus.OK)
|
||||||
async def api_links(
|
async def api_links(
|
||||||
req: Request,
|
req: Request,
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type),
|
key_info: WalletTypeInfo = Depends(require_invoice_key),
|
||||||
all_wallets: bool = Query(False),
|
all_wallets: bool = Query(False),
|
||||||
):
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [key_info.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
user = await get_user(wallet.wallet.user)
|
user = await get_user(key_info.wallet.user)
|
||||||
wallet_ids = user.wallet_ids if user else []
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -189,7 +188,10 @@ async def api_link_create_or_update(
|
||||||
if data.username and data.username != link.username:
|
if data.username and data.username != link.username:
|
||||||
await check_username_exists(data.username)
|
await check_username_exists(data.username)
|
||||||
|
|
||||||
link = await update_pay_link(**data.dict(), link_id=link_id)
|
for k, v in data.dict().items():
|
||||||
|
setattr(link, k, v)
|
||||||
|
|
||||||
|
link = await update_pay_link(link)
|
||||||
else:
|
else:
|
||||||
if data.username:
|
if data.username:
|
||||||
await check_username_exists(data.username)
|
await check_username_exists(data.username)
|
||||||
|
|
@ -201,7 +203,9 @@ async def api_link_create_or_update(
|
||||||
|
|
||||||
|
|
||||||
@lnurlp_api_router.delete("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
@lnurlp_api_router.delete("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||||
async def api_link_delete(link_id: str, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_link_delete(
|
||||||
|
link_id: str, key_info: WalletTypeInfo = Depends(require_admin_key)
|
||||||
|
):
|
||||||
link = await get_pay_link(link_id)
|
link = await get_pay_link(link_id)
|
||||||
|
|
||||||
if not link:
|
if not link:
|
||||||
|
|
@ -210,9 +214,9 @@ async def api_link_delete(link_id: str, wallet: WalletTypeInfo = Depends(get_key
|
||||||
)
|
)
|
||||||
|
|
||||||
# admins are allowed to delete paylinks beloging to regular users
|
# admins are allowed to delete paylinks beloging to regular users
|
||||||
user = await get_user(wallet.wallet.user)
|
user = await get_user(key_info.wallet.user)
|
||||||
admin_user = user.admin if user else False
|
admin_user = user.admin if user else False
|
||||||
if not admin_user and link.wallet != wallet.wallet.id:
|
if not admin_user and link.wallet != key_info.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
|
detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@ from pydantic import parse_obj_as
|
||||||
from .crud import (
|
from .crud import (
|
||||||
get_address_data,
|
get_address_data,
|
||||||
get_or_create_lnurlp_settings,
|
get_or_create_lnurlp_settings,
|
||||||
increment_pay_link,
|
get_pay_link,
|
||||||
|
update_pay_link,
|
||||||
)
|
)
|
||||||
|
|
||||||
lnurlp_lnurl_router = APIRouter()
|
lnurlp_lnurl_router = APIRouter()
|
||||||
|
|
@ -36,11 +37,13 @@ async def api_lnurl_callback(
|
||||||
amount: int = Query(...),
|
amount: int = Query(...),
|
||||||
webhook_data: str = Query(None),
|
webhook_data: str = Query(None),
|
||||||
):
|
):
|
||||||
link = await increment_pay_link(link_id, served_pr=1)
|
link = await get_pay_link(link_id)
|
||||||
if not link:
|
if not link:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist."
|
status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist."
|
||||||
)
|
)
|
||||||
|
link.served_pr = 1
|
||||||
|
await update_pay_link(link)
|
||||||
mininum = link.min
|
mininum = link.min
|
||||||
maximum = link.max
|
maximum = link.max
|
||||||
|
|
||||||
|
|
@ -136,13 +139,15 @@ async def api_lnurl_callback(
|
||||||
name="lnurlp.api_lnurl_response",
|
name="lnurlp.api_lnurl_response",
|
||||||
)
|
)
|
||||||
async def api_lnurl_response(
|
async def api_lnurl_response(
|
||||||
request: Request, link_id, webhook_data: Optional[str] = Query(None)
|
request: Request, link_id: str, webhook_data: Optional[str] = Query(None)
|
||||||
):
|
):
|
||||||
link = await increment_pay_link(link_id, served_meta=1)
|
link = await get_pay_link(link_id)
|
||||||
if not link:
|
if not link:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist."
|
status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist."
|
||||||
)
|
)
|
||||||
|
link.served_meta = 1
|
||||||
|
await update_pay_link(link)
|
||||||
|
|
||||||
rate = await get_fiat_rate_satoshis(link.currency) if link.currency else 1
|
rate = await get_fiat_rate_satoshis(link.currency) if link.currency else 1
|
||||||
url = request.url_for("lnurlp.api_lnurl_callback", link_id=link.id)
|
url = request.url_for("lnurlp.api_lnurl_callback", link_id=link.id)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue