Extension: LNURLw webhook_url (#610)
* LNURLw web_hook * crlf -> lf * Fix typo * LNURLw webhook api doc
This commit is contained in:
parent
7c4ce9bf96
commit
895d9d2e0a
7 changed files with 54 additions and 7 deletions
|
|
@ -25,9 +25,10 @@ async def create_withdraw_link(
|
||||||
unique_hash,
|
unique_hash,
|
||||||
k1,
|
k1,
|
||||||
open_time,
|
open_time,
|
||||||
usescsv
|
usescsv,
|
||||||
|
webhook_url
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
link_id,
|
link_id,
|
||||||
|
|
@ -42,6 +43,7 @@ async def create_withdraw_link(
|
||||||
urlsafe_short_hash(),
|
urlsafe_short_hash(),
|
||||||
int(datetime.now().timestamp()) + data.wait_time,
|
int(datetime.now().timestamp()) + data.wait_time,
|
||||||
usescsv,
|
usescsv,
|
||||||
|
data.webhook_url
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
link = await get_withdraw_link(link_id, 0)
|
link = await get_withdraw_link(link_id, 0)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
import json
|
import json
|
||||||
|
import traceback
|
||||||
|
import httpx
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
|
|
@ -103,17 +106,35 @@ async def api_lnurl_callback(
|
||||||
await update_withdraw_link(link.id, **changes)
|
await update_withdraw_link(link.id, **changes)
|
||||||
|
|
||||||
payment_request = pr
|
payment_request = pr
|
||||||
|
|
||||||
await pay_invoice(
|
payment_hash = await pay_invoice(
|
||||||
wallet_id=link.wallet,
|
wallet_id=link.wallet,
|
||||||
payment_request=payment_request,
|
payment_request=payment_request,
|
||||||
max_sat=link.max_withdrawable,
|
max_sat=link.max_withdrawable,
|
||||||
extra={"tag": "withdraw"},
|
extra={"tag": "withdraw"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if link.webhook_url:
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
r = await client.post(
|
||||||
|
link.webhook_url,
|
||||||
|
json={
|
||||||
|
"payment_hash": payment_hash,
|
||||||
|
"payment_request": payment_request,
|
||||||
|
"lnurlw": link.id,
|
||||||
|
},
|
||||||
|
timeout=40,
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
|
||||||
|
print("Caught exception when dispatching webhook url:", exc)
|
||||||
|
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await update_withdraw_link(link.id, **changesback)
|
await update_withdraw_link(link.id, **changesback)
|
||||||
|
print(traceback.format_exc())
|
||||||
return {"status": "ERROR", "reason": "Link not working"}
|
return {"status": "ERROR", "reason": "Link not working"}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,3 +108,9 @@ async def m003_make_hash_check(db):
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def m004_webhook_url(db):
|
||||||
|
"""
|
||||||
|
Adds webhook_url
|
||||||
|
"""
|
||||||
|
await db.execute("ALTER TABLE withdraw.withdraw_link ADD COLUMN webhook_url TEXT;")
|
||||||
|
|
@ -15,6 +15,7 @@ class CreateWithdrawData(BaseModel):
|
||||||
uses: int = Query(..., ge=1)
|
uses: int = Query(..., ge=1)
|
||||||
wait_time: int = Query(..., ge=1)
|
wait_time: int = Query(..., ge=1)
|
||||||
is_unique: bool
|
is_unique: bool
|
||||||
|
webhook_url: str = Query(None)
|
||||||
|
|
||||||
|
|
||||||
class WithdrawLink(BaseModel):
|
class WithdrawLink(BaseModel):
|
||||||
|
|
@ -32,6 +33,7 @@ class WithdrawLink(BaseModel):
|
||||||
used: int = Query(0)
|
used: int = Query(0)
|
||||||
usescsv: str = Query(None)
|
usescsv: str = Query(None)
|
||||||
number: int = Query(0)
|
number: int = Query(0)
|
||||||
|
webhook_url: str = Query(None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_spent(self) -> bool:
|
def is_spent(self) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,8 @@ new Vue({
|
||||||
'max_withdrawable',
|
'max_withdrawable',
|
||||||
'uses',
|
'uses',
|
||||||
'wait_time',
|
'wait_time',
|
||||||
'is_unique'
|
'is_unique',
|
||||||
|
'webhook_url'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@
|
||||||
<code
|
<code
|
||||||
>{"title": <string>, "min_withdrawable": <integer>,
|
>{"title": <string>, "min_withdrawable": <integer>,
|
||||||
"max_withdrawable": <integer>, "uses": <integer>,
|
"max_withdrawable": <integer>, "uses": <integer>,
|
||||||
"wait_time": <integer>, "is_unique": <boolean>}</code
|
"wait_time": <integer>, "is_unique": <boolean>,
|
||||||
|
"webhook_url": <string>}</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)
|
||||||
|
|
@ -81,7 +82,7 @@
|
||||||
>curl -X POST {{ request.base_url }}withdraw/api/v1/links -d '{"title":
|
>curl -X POST {{ request.base_url }}withdraw/api/v1/links -d '{"title":
|
||||||
<string>, "min_withdrawable": <integer>,
|
<string>, "min_withdrawable": <integer>,
|
||||||
"max_withdrawable": <integer>, "uses": <integer>,
|
"max_withdrawable": <integer>, "uses": <integer>,
|
||||||
"wait_time": <integer>, "is_unique": <boolean>}' -H
|
"wait_time": <integer>, "is_unique": <boolean>, "webhook_url": <string>}' -H
|
||||||
"Content-type: application/json" -H "X-Api-Key: {{
|
"Content-type: application/json" -H "X-Api-Key: {{
|
||||||
user.wallets[0].adminkey }}"
|
user.wallets[0].adminkey }}"
|
||||||
</code>
|
</code>
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
{{ col.label }}
|
{{ col.label }}
|
||||||
</q-th>
|
</q-th>
|
||||||
<q-th auto-width></q-th>
|
<q-th auto-width></q-th>
|
||||||
|
<q-th auto-width></q-th>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:body="props">
|
<template v-slot:body="props">
|
||||||
|
|
@ -81,6 +82,11 @@
|
||||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
{{ col.value }}
|
{{ col.value }}
|
||||||
</q-td>
|
</q-td>
|
||||||
|
<q-td>
|
||||||
|
<q-icon v-if="props.row.webhook_url" size="14px" name="http">
|
||||||
|
<q-tooltip>Webhook to {{ props.row.webhook_url}}</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</q-td>
|
||||||
<q-td auto-width>
|
<q-td auto-width>
|
||||||
<q-btn
|
<q-btn
|
||||||
flat
|
flat
|
||||||
|
|
@ -143,6 +149,14 @@
|
||||||
</q-select>
|
</q-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<q-input
|
||||||
|
filled
|
||||||
|
dense
|
||||||
|
v-model="formDialog.data.webhook_url"
|
||||||
|
type="text"
|
||||||
|
label="Webhook URL (optional)"
|
||||||
|
hint="A URL to be called whenever this link gets used."
|
||||||
|
></q-input>
|
||||||
<q-list>
|
<q-list>
|
||||||
<q-item tag="label" class="rounded-borders">
|
<q-item tag="label" class="rounded-borders">
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue