mirror of
https://github.com/lnbits/lnbits.git
synced 2025-09-29 13:22:37 +02:00
fix: lnurlp, withdraw
This commit is contained in:
@@ -27,4 +27,3 @@ print(
|
|||||||
- service fee: {SERVICE_FEE}
|
- service fee: {SERVICE_FEE}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -1,34 +1,48 @@
|
|||||||
|
import asyncio
|
||||||
|
|
||||||
from fastapi import APIRouter, FastAPI
|
from fastapi import APIRouter, FastAPI
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from starlette.routing import Mount
|
from starlette.routing import Mount
|
||||||
|
|
||||||
from lnbits.db import Database
|
from lnbits.db import Database
|
||||||
|
from lnbits.helpers import template_renderer
|
||||||
|
from lnbits.tasks import catch_everything_and_restart
|
||||||
|
|
||||||
db = Database("ext_lnurlp")
|
db = Database("ext_lnurlp")
|
||||||
|
|
||||||
|
lnurlp_static_files = [
|
||||||
|
{
|
||||||
|
"path": "/lnurlp/static",
|
||||||
|
"app": StaticFiles(directory="lnbits/extensions/lnurlp/static"),
|
||||||
|
"name": "lnurlp_static",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
lnurlp_ext: APIRouter = APIRouter(
|
lnurlp_ext: APIRouter = APIRouter(
|
||||||
prefix="/lnurlp",
|
prefix="/lnurlp",
|
||||||
static_folder="static",
|
tags=["lnurlp"]
|
||||||
# "lnurlp", __name__, static_folder="static", template_folder="templates"
|
# "lnurlp", __name__, static_folder="static", template_folder="templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
def lnurlp_renderer():
|
def lnurlp_renderer():
|
||||||
return template_renderer(
|
return template_renderer(
|
||||||
[
|
[
|
||||||
"lnbits/extensions/lnticket/templates",
|
"lnbits/extensions/lnurlp/templates",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
from .views_api import * # noqa
|
from .views_api import * # noqa
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
|
from .tasks import wait_for_paid_invoices
|
||||||
|
|
||||||
|
def lnurlp_start():
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
|
||||||
|
|
||||||
|
|
||||||
@lnurlp_ext.on_event("startup")
|
|
||||||
def _do_it():
|
|
||||||
register_listeners()
|
|
||||||
|
|
||||||
# from .lnurl import * # noqa
|
# from .lnurl import * # noqa
|
||||||
# from .tasks import register_listeners
|
|
||||||
|
|
||||||
# from lnbits.tasks import record_async
|
# from lnbits.tasks import record_async
|
||||||
|
|
||||||
|
@@ -2,25 +2,17 @@ from typing import List, Optional, Union
|
|||||||
|
|
||||||
from lnbits.db import SQLITE
|
from lnbits.db import SQLITE
|
||||||
from . import db
|
from . import db
|
||||||
from .models import PayLink
|
from .models import PayLink, CreatePayLinkData
|
||||||
|
|
||||||
|
|
||||||
async def create_pay_link(
|
async def create_pay_link(
|
||||||
*,
|
data: CreatePayLinkData,
|
||||||
wallet_id: str,
|
wallet_id: str
|
||||||
description: str,
|
|
||||||
min: int,
|
|
||||||
max: int,
|
|
||||||
comment_chars: int = 0,
|
|
||||||
currency: Optional[str] = None,
|
|
||||||
webhook_url: Optional[str] = None,
|
|
||||||
success_text: Optional[str] = None,
|
|
||||||
success_url: Optional[str] = None,
|
|
||||||
) -> PayLink:
|
) -> PayLink:
|
||||||
|
|
||||||
returning = "" if db.type == SQLITE else "RETURNING ID"
|
returning = "" if db.type == SQLITE else "RETURNING ID"
|
||||||
method = db.execute if db.type == SQLITE else db.fetchone
|
method = db.execute if db.type == SQLITE else db.fetchone
|
||||||
|
print("CPL", wallet_id, data)
|
||||||
result = await (method)(
|
result = await (method)(
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO lnurlp.pay_links (
|
INSERT INTO lnurlp.pay_links (
|
||||||
@@ -41,14 +33,14 @@ async def create_pay_link(
|
|||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
wallet_id,
|
wallet_id,
|
||||||
description,
|
data.description,
|
||||||
min,
|
data.min,
|
||||||
max,
|
data.max,
|
||||||
webhook_url,
|
data.webhook_url,
|
||||||
success_text,
|
data.success_text,
|
||||||
success_url,
|
data.success_url,
|
||||||
comment_chars,
|
data.comment_chars,
|
||||||
currency,
|
data.currency,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if db.type == SQLITE:
|
if db.type == SQLITE:
|
||||||
|
@@ -11,7 +11,7 @@ from . import lnurlp_ext
|
|||||||
from .crud import increment_pay_link
|
from .crud import increment_pay_link
|
||||||
|
|
||||||
|
|
||||||
@lnurlp_ext.get("/api/v1/lnurl/{link_id}", status_code=HTTPStatus.OK)
|
@lnurlp_ext.get("/api/v1/lnurl/{link_id}", status_code=HTTPStatus.OK, name="lnurlp.api_lnurl_response")
|
||||||
async def api_lnurl_response(request: Request, link_id):
|
async def api_lnurl_response(request: Request, link_id):
|
||||||
link = await increment_pay_link(link_id, served_meta=1)
|
link = await increment_pay_link(link_id, served_meta=1)
|
||||||
if not link:
|
if not link:
|
||||||
|
@@ -1,12 +1,23 @@
|
|||||||
import json
|
import json
|
||||||
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
|
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
|
||||||
from quart import url_for
|
from starlette.requests import Request
|
||||||
|
from fastapi.param_functions import Query
|
||||||
from typing import Optional, Dict
|
from typing import Optional, Dict
|
||||||
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
||||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
class CreatePayLinkData(BaseModel):
|
||||||
|
description: str
|
||||||
|
min: int = Query(0.01, ge=0.01)
|
||||||
|
max: int = Query(0.01, ge=0.01)
|
||||||
|
currency: str = Query(None)
|
||||||
|
comment_chars: int = Query(0, ge=0, lt=800)
|
||||||
|
webhook_url: str = Query(None)
|
||||||
|
success_text: str = Query(None)
|
||||||
|
success_url: str = Query(None)
|
||||||
|
|
||||||
class PayLink(BaseModel):
|
class PayLink(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
wallet: str
|
wallet: str
|
||||||
@@ -14,10 +25,10 @@ class PayLink(BaseModel):
|
|||||||
min: int
|
min: int
|
||||||
served_meta: int
|
served_meta: int
|
||||||
served_pr: int
|
served_pr: int
|
||||||
webhook_url: str
|
webhook_url: Optional[str]
|
||||||
success_text: str
|
success_text: Optional[str]
|
||||||
success_url: str
|
success_url: Optional[str]
|
||||||
currency: str
|
currency: Optional[str]
|
||||||
comment_chars: int
|
comment_chars: int
|
||||||
max: int
|
max: int
|
||||||
|
|
||||||
@@ -28,7 +39,8 @@ class PayLink(BaseModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def lnurl(self) -> str:
|
def lnurl(self) -> str:
|
||||||
url = url_for("lnurlp.api_lnurl_response", link_id=self.id, _external=True)
|
r = Request
|
||||||
|
url = r.url_for("lnurlp.api_lnurl_response", link_id=self.id, _external=True)
|
||||||
return lnurl_encode(url)
|
return lnurl_encode(url)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import trio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
@@ -9,17 +9,14 @@ from lnbits.tasks import register_invoice_listener
|
|||||||
from .crud import get_pay_link
|
from .crud import get_pay_link
|
||||||
|
|
||||||
|
|
||||||
async def register_listeners():
|
async def wait_for_paid_invoices():
|
||||||
invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
invoice_queue = asyncio.Queue()
|
||||||
register_invoice_listener(invoice_paid_chan_send)
|
register_invoice_listener(invoice_queue)
|
||||||
await wait_for_paid_invoices(invoice_paid_chan_recv)
|
|
||||||
|
|
||||||
|
while True:
|
||||||
async def wait_for_paid_invoices(invoice_paid_chan: trio.MemoryReceiveChannel):
|
payment = await invoice_queue.get()
|
||||||
async for payment in invoice_paid_chan:
|
|
||||||
await on_invoice_paid(payment)
|
await on_invoice_paid(payment)
|
||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
if "lnurlp" != payment.extra.get("tag"):
|
if "lnurlp" != payment.extra.get("tag"):
|
||||||
# not an lnurlp invoice
|
# not an lnurlp invoice
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
<code
|
<code
|
||||||
>curl -X GET {{ request.url_root }}api/v1/links -H "X-Api-Key: {{
|
>curl -X GET {{ request.url_root }}api/v1/links -H "X-Api-Key: {{
|
||||||
g.user.wallets[0].inkey }}"
|
user.wallets[0].inkey }}"
|
||||||
</code>
|
</code>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
@@ -27,7 +27,8 @@
|
|||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<code
|
<code
|
||||||
><span class="text-blue">GET</span> /lnurlp/api/v1/links/<pay_id></code
|
><span class="text-blue">GET</span>
|
||||||
|
/lnurlp/api/v1/links/<pay_id></code
|
||||||
>
|
>
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
<code>{"X-Api-Key": <invoice_key>}</code><br />
|
<code>{"X-Api-Key": <invoice_key>}</code><br />
|
||||||
@@ -39,7 +40,7 @@
|
|||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
<code
|
<code
|
||||||
>curl -X GET {{ request.url_root }}api/v1/links/<pay_id> -H
|
>curl -X GET {{ request.url_root }}api/v1/links/<pay_id> -H
|
||||||
"X-Api-Key: {{ g.user.wallets[0].inkey }}"
|
"X-Api-Key: {{ user.wallets[0].inkey }}"
|
||||||
</code>
|
</code>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
@@ -56,7 +57,11 @@
|
|||||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
<code>{"X-Api-Key": <admin_key>}</code><br />
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||||
<code>{"description": <string> "amount": <integer> "max": <integer> "min": <integer> "comment_chars": <integer>}</code>
|
<code
|
||||||
|
>{"description": <string> "amount": <integer> "max":
|
||||||
|
<integer> "min": <integer> "comment_chars":
|
||||||
|
<integer>}</code
|
||||||
|
>
|
||||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||||
Returns 201 CREATED (application/json)
|
Returns 201 CREATED (application/json)
|
||||||
</h5>
|
</h5>
|
||||||
@@ -64,8 +69,10 @@
|
|||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
<code
|
<code
|
||||||
>curl -X POST {{ request.url_root }}api/v1/links -d '{"description":
|
>curl -X POST {{ request.url_root }}api/v1/links -d '{"description":
|
||||||
<string>, "amount": <integer>, "max": <integer>, "min": <integer>, "comment_chars": <integer>}' -H "Content-type:
|
<string>, "amount": <integer>, "max": <integer>,
|
||||||
application/json" -H "X-Api-Key: {{ g.user.wallets[0].adminkey }}"
|
"min": <integer>, "comment_chars": <integer>}' -H
|
||||||
|
"Content-type: application/json" -H "X-Api-Key: {{
|
||||||
|
user.wallets[0].adminkey }}"
|
||||||
</code>
|
</code>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
@@ -95,7 +102,7 @@
|
|||||||
>curl -X PUT {{ request.url_root }}api/v1/links/<pay_id> -d
|
>curl -X PUT {{ request.url_root }}api/v1/links/<pay_id> -d
|
||||||
'{"description": <string>, "amount": <integer>}' -H
|
'{"description": <string>, "amount": <integer>}' -H
|
||||||
"Content-type: application/json" -H "X-Api-Key: {{
|
"Content-type: application/json" -H "X-Api-Key: {{
|
||||||
g.user.wallets[0].adminkey }}"
|
user.wallets[0].adminkey }}"
|
||||||
</code>
|
</code>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
@@ -120,7 +127,7 @@
|
|||||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||||
<code
|
<code
|
||||||
>curl -X DELETE {{ request.url_root }}api/v1/links/<pay_id> -H
|
>curl -X DELETE {{ request.url_root }}api/v1/links/<pay_id> -H
|
||||||
"X-Api-Key: {{ g.user.wallets[0].adminkey }}"
|
"X-Api-Key: {{ user.wallets[0].adminkey }}"
|
||||||
</code>
|
</code>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from lnbits.decorators import check_user_exists, validate_uuids
|
from lnbits.decorators import check_user_exists
|
||||||
|
|
||||||
from . import lnurlp_ext, lnurlp_renderer
|
from . import lnurlp_ext, lnurlp_renderer
|
||||||
from .crud import get_pay_link
|
from .crud import get_pay_link
|
||||||
@@ -15,7 +15,7 @@ from lnbits.core.models import User
|
|||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
@lnurlp_ext.get("/", response_class=HTMLResponse)
|
@lnurlp_ext.get("/", response_class=HTMLResponse)
|
||||||
@validate_uuids(["usr"], required=True)
|
# @validate_uuids(["usr"], required=True)
|
||||||
# @check_user_exists()
|
# @check_user_exists()
|
||||||
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("lnurlp/index.html", {"request": request, "user": user.dict()})
|
return lnurlp_renderer().TemplateResponse("lnurlp/index.html", {"request": request, "user": user.dict()})
|
||||||
|
@@ -10,8 +10,9 @@ from starlette.requests import Request
|
|||||||
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||||
from lnbits.utils.exchange_rates import currencies, get_fiat_rate_satoshis
|
from lnbits.utils.exchange_rates import currencies, get_fiat_rate_satoshis
|
||||||
|
from .models import CreatePayLinkData
|
||||||
|
|
||||||
from . import lnurlp_ext
|
from . import lnurlp_ext
|
||||||
from .crud import (
|
from .crud import (
|
||||||
@@ -75,20 +76,11 @@ async def api_link_retrieve(link_id, wallet: WalletTypeInfo = Depends(get_key_ty
|
|||||||
|
|
||||||
return {**link._asdict(), **{"lnurl": link.lnurl}}
|
return {**link._asdict(), **{"lnurl": link.lnurl}}
|
||||||
|
|
||||||
class CreateData(BaseModel):
|
|
||||||
description: str
|
|
||||||
min: int = Query(0.01, ge=0.01)
|
|
||||||
max: int = Query(0.01, ge=0.01)
|
|
||||||
currency: Optional[str]
|
|
||||||
comment_chars: int = Query(0, ge=0, lt=800)
|
|
||||||
webhook_url: Optional[str]
|
|
||||||
success_text: Optional[str]
|
|
||||||
success_url: Optional[str]
|
|
||||||
|
|
||||||
@lnurlp_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)
|
@lnurlp_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)
|
||||||
@lnurlp_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
@lnurlp_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||||
# @api_check_wallet_key("invoice")
|
# @api_check_wallet_key("invoice")
|
||||||
async def api_link_create_or_update(data: CreateData, link_id=None, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_link_create_or_update(data: CreatePayLinkData, link_id=None, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
if data.min > data.max:
|
if data.min > data.max:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
detail="Min is greater than max.",
|
detail="Min is greater than max.",
|
||||||
@@ -128,18 +120,18 @@ async def api_link_create_or_update(data: CreateData, link_id=None, wallet: Wall
|
|||||||
# HTTPStatus.NOT_FOUND,
|
# HTTPStatus.NOT_FOUND,
|
||||||
# )
|
# )
|
||||||
|
|
||||||
if link.wallet != g.wallet.id:
|
if link.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
detail="Not your pay link.",
|
detail="Not your pay link.",
|
||||||
status_code=HTTPStatus.FORBIDDEN
|
status_code=HTTPStatus.FORBIDDEN
|
||||||
)
|
)
|
||||||
# return {"message": "Not your pay link."}, HTTPStatus.FORBIDDEN
|
# return {"message": "Not your pay link."}, HTTPStatus.FORBIDDEN
|
||||||
|
|
||||||
link = await update_pay_link(link_id, **data)
|
link = await update_pay_link(link_id, data)
|
||||||
else:
|
else:
|
||||||
link = await create_pay_link(wallet_id=wallet.wallet.id, **data)
|
link = await create_pay_link(data, wallet_id=wallet.wallet.id)
|
||||||
|
print("LINK", link)
|
||||||
return {**link._asdict(), **{"lnurl": link.lnurl}}
|
return {**link.dict(), "lnurl": link.lnurl}
|
||||||
|
|
||||||
|
|
||||||
@lnurlp_ext.delete("/api/v1/links/{link_id}")
|
@lnurlp_ext.delete("/api/v1/links/{link_id}")
|
||||||
|
@@ -1,13 +1,23 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
from lnbits.db import Database
|
from lnbits.db import Database
|
||||||
|
from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_withdraw")
|
db = Database("ext_withdraw")
|
||||||
|
|
||||||
|
withdraw_static_files = [
|
||||||
|
{
|
||||||
|
"path": "/withdraw/static",
|
||||||
|
"app": StaticFiles(directory="lnbits/extensions/withdraw/static"),
|
||||||
|
"name": "withdraw_static",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
withdraw_ext: APIRouter = APIRouter(
|
withdraw_ext: APIRouter = APIRouter(
|
||||||
prefix="/withdraw",
|
prefix="/withdraw",
|
||||||
static_folder="static"
|
tags=["withdraw"],
|
||||||
# "withdraw", __name__, static_folder="static", template_folder="templates"
|
# "withdraw", __name__, static_folder="static", template_folder="templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,6 +33,7 @@ from .views_api import * # noqa
|
|||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
from .lnurl import * # noqa
|
from .lnurl import * # noqa
|
||||||
|
|
||||||
@withdraw_ext.on_event("startup")
|
|
||||||
def _do_it():
|
# @withdraw_ext.on_event("startup")
|
||||||
register_listeners()
|
# def _do_it():
|
||||||
|
# register_listeners()
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import shortuuid # type: ignore
|
import shortuuid # type: ignore
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from quart import jsonify, request
|
|
||||||
|
|
||||||
from lnbits.core.services import pay_invoice
|
from lnbits.core.services import pay_invoice
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
from quart import url_for
|
from fastapi import Request
|
||||||
from lnurl import Lnurl, LnurlWithdrawResponse, encode as lnurl_encode # type: ignore
|
from lnurl import Lnurl, LnurlWithdrawResponse, encode as lnurl_encode # type: ignore
|
||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -33,19 +33,19 @@ class WithdrawLink(BaseModel):
|
|||||||
return self.used >= self.uses
|
return self.used >= self.uses
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lnurl(self) -> Lnurl:
|
def lnurl(self, req: Request) -> Lnurl:
|
||||||
if self.is_unique:
|
if self.is_unique:
|
||||||
usescssv = self.usescsv.split(",")
|
usescssv = self.usescsv.split(",")
|
||||||
tohash = self.id + self.unique_hash + usescssv[self.number]
|
tohash = self.id + self.unique_hash + usescssv[self.number]
|
||||||
multihash = shortuuid.uuid(name=tohash)
|
multihash = shortuuid.uuid(name=tohash)
|
||||||
url = url_for(
|
url = req.url_for(
|
||||||
"withdraw.api_lnurl_multi_response",
|
"withdraw.api_lnurl_multi_response",
|
||||||
unique_hash=self.unique_hash,
|
unique_hash=self.unique_hash,
|
||||||
id_unique_hash=multihash,
|
id_unique_hash=multihash,
|
||||||
_external=True,
|
_external=True,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
url = url_for(
|
url = req.url_for(
|
||||||
"withdraw.api_lnurl_response",
|
"withdraw.api_lnurl_response",
|
||||||
unique_hash=self.unique_hash,
|
unique_hash=self.unique_hash,
|
||||||
_external=True,
|
_external=True,
|
||||||
@@ -55,7 +55,7 @@ class WithdrawLink(BaseModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def lnurl_response(self) -> LnurlWithdrawResponse:
|
def lnurl_response(self) -> LnurlWithdrawResponse:
|
||||||
url = url_for(
|
url = req.url_for(
|
||||||
"withdraw.api_lnurl_callback", unique_hash=self.unique_hash, _external=True
|
"withdraw.api_lnurl_callback", unique_hash=self.unique_hash, _external=True
|
||||||
)
|
)
|
||||||
return LnurlWithdrawResponse(
|
return LnurlWithdrawResponse(
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import pyqrcode
|
import pyqrcode
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from lnbits.decorators import check_user_exists, validate_uuids
|
from lnbits.decorators import check_user_exists
|
||||||
|
|
||||||
from . import withdraw_ext, withdraw_renderer
|
from . import withdraw_ext, withdraw_renderer
|
||||||
from .crud import get_withdraw_link, chunks
|
from .crud import get_withdraw_link, chunks
|
||||||
@@ -16,7 +16,7 @@ from lnbits.core.models import User
|
|||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
@withdraw_ext.get("/", response_class=HTMLResponse)
|
@withdraw_ext.get("/", response_class=HTMLResponse)
|
||||||
@validate_uuids(["usr"], required=True)
|
# @validate_uuids(["usr"], required=True)
|
||||||
# @check_user_exists()
|
# @check_user_exists()
|
||||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return withdraw_renderer().TemplateResponse("withdraw/index.html", {"request":request,"user": user.dict()})
|
return withdraw_renderer().TemplateResponse("withdraw/index.html", {"request":request,"user": user.dict()})
|
||||||
@@ -36,7 +36,7 @@ async def display(request: Request, link_id):
|
|||||||
|
|
||||||
|
|
||||||
@withdraw_ext.get("/img/{link_id}", response_class=HTMLResponse)
|
@withdraw_ext.get("/img/{link_id}", response_class=HTMLResponse)
|
||||||
async def img(request: Request, link_id, response: Response):
|
async def img(request: Request, link_id):
|
||||||
link = await get_withdraw_link(link_id, 0)
|
link = await get_withdraw_link(link_id, 0)
|
||||||
if not link:
|
if not link:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
@@ -9,7 +9,7 @@ from starlette.requests import Request
|
|||||||
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
from starlette.responses import HTMLResponse, JSONResponse # type: ignore
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
from lnbits.decorators import api_check_wallet_key, api_validate_post_request
|
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||||
|
|
||||||
# from fastapi import FastAPI, Query, Response
|
# from fastapi import FastAPI, Query, Response
|
||||||
|
|
||||||
@@ -83,8 +83,8 @@ class CreateData(BaseModel):
|
|||||||
|
|
||||||
@withdraw_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)
|
@withdraw_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED)
|
||||||
@withdraw_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
@withdraw_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||||
@api_check_wallet_key("admin")
|
# @api_check_wallet_key("admin")
|
||||||
async def api_link_create_or_update(data: CreateData, link_id: str = None, response: Response):
|
async def api_link_create_or_update(data: CreateData, link_id: str = None):
|
||||||
if data.max_withdrawable < data.min_withdrawable:
|
if data.max_withdrawable < data.min_withdrawable:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
detail="`max_withdrawable` needs to be at least `min_withdrawable`.",
|
detail="`max_withdrawable` needs to be at least `min_withdrawable`.",
|
||||||
|
Reference in New Issue
Block a user