configuration for nostr

This commit is contained in:
callebtc 2023-04-24 17:12:35 +02:00
commit 64da75d605
7 changed files with 170 additions and 95 deletions

View file

@ -58,10 +58,11 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
comment_chars, comment_chars,
currency, currency,
fiat_base_multiplier, fiat_base_multiplier,
username username,
zaps
) )
VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", """,
( (
link_id, link_id,
@ -78,6 +79,7 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
data.currency, data.currency,
data.fiat_base_multiplier, data.fiat_base_multiplier,
data.username, data.username,
data.zaps,
), ),
) )
assert result assert result

View file

@ -147,6 +147,7 @@ async def api_lnurl_response(request: Request, link_id, lnaddress=False):
if link.comment_chars > 0: if link.comment_chars > 0:
params["commentAllowed"] = link.comment_chars params["commentAllowed"] = link.comment_chars
if link.zaps:
params["allowsNostr"] = True params["allowsNostr"] = True
params["nostrPubkey"] = nostr_publickey.hex() params["nostrPubkey"] = nostr_publickey.hex()
return params return params

View file

@ -150,6 +150,13 @@ async def m006_redux(db):
async def m007_add_lnaddress_username(db): async def m007_add_lnaddress_username(db):
""" """
Add headers and body to webhooks Add Lightning address to pay links
""" """
await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN username TEXT;") await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN username TEXT;")
async def m008_add_zap_enabled_column(db):
"""
Add Nostr zaps to pay links
"""
await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN zaps BOOLEAN;")

View file

@ -24,6 +24,7 @@ class CreatePayLinkData(BaseModel):
success_url: str = Query(None) success_url: str = Query(None)
fiat_base_multiplier: int = Query(100, ge=1) fiat_base_multiplier: int = Query(100, ge=1)
username: str = Query(None) username: str = Query(None)
zaps: bool = Query(False)
class PayLink(BaseModel): class PayLink(BaseModel):
@ -34,6 +35,7 @@ class PayLink(BaseModel):
served_meta: int served_meta: int
served_pr: int served_pr: int
username: Optional[str] username: Optional[str]
zaps: Optional[bool]
domain: Optional[str] domain: Optional[str]
webhook_url: Optional[str] webhook_url: Optional[str]
webhook_headers: Optional[str] webhook_headers: Optional[str]

View file

@ -40,7 +40,9 @@ new Vue({
formDialog: { formDialog: {
show: false, show: false,
fixedAmount: true, fixedAmount: true,
data: {} data: {
zaps:false
}
}, },
qrCodeDialog: { qrCodeDialog: {
show: false, show: false,
@ -140,7 +142,8 @@ new Vue({
'success_url', 'success_url',
'comment_chars', 'comment_chars',
'currency', 'currency',
'username' 'username',
'zaps'
), ),
(value, key) => (value, key) =>
(key === 'webhook_url' || (key === 'webhook_url' ||

View file

@ -72,9 +72,9 @@ async def on_invoice_paid(payment: Payment):
) )
# NIP-57 # NIP-57
# load the zap request
nostr = payment.extra.get("nostr") nostr = payment.extra.get("nostr")
if nostr: if pay_link and pay_link.zaps and nostr:
event_json = json.loads(nostr) event_json = json.loads(nostr)
def get_tag(event_json, tag): def get_tag(event_json, tag):
@ -114,7 +114,7 @@ async def on_invoice_paid(payment: Payment):
wsts: List[Thread] = [] wsts: List[Thread] = []
# # send zap via nostrclient # # send zap via nostrclient
# ws, wst = send_zap(f"ws://localhost:{settings.port}/nostrclient/api/v1/relay") # ws, wst = send_zap(f"wss://localhost:{settings.port}/nostrclient/api/v1/relay")
# wss += [ws] # wss += [ws]
# wsts += [wst] # wsts += [wst]
@ -138,7 +138,6 @@ async def on_invoice_paid(payment: Payment):
async def mark_webhook_sent( async def mark_webhook_sent(
payment_hash: str, status: int, is_success: bool, reason_phrase="", text="" payment_hash: str, status: int, is_success: bool, reason_phrase="", text=""
) -> None: ) -> None:
await update_payment_extra( await update_payment_extra(
payment_hash, payment_hash,
{ {

View file

@ -48,7 +48,8 @@
type="a" type="a"
:href="props.row.pay_url" :href="props.row.pay_url"
target="_blank" target="_blank"
><q-tooltip>Sharable Page</q-tooltip></q-btn> ><q-tooltip>Sharable Page</q-tooltip></q-btn
>
<q-btn <q-btn
unelevated unelevated
dense dense
@ -56,7 +57,8 @@
icon="visibility" icon="visibility"
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
@click="openQrCodeDialog(props.row.id)" @click="openQrCodeDialog(props.row.id)"
><q-tooltip>View Link</q-tooltip></q-btn> ><q-tooltip>View Link</q-tooltip></q-btn
>
</q-td> </q-td>
<q-td auto-width>{{ props.row.description }}</q-td> <q-td auto-width>{{ props.row.description }}</q-td>
<q-td auto-width> <q-td auto-width>
@ -66,10 +68,14 @@
<span v-else>{{ props.row.min }} - {{ props.row.max }}</span> <span v-else>{{ props.row.min }} - {{ props.row.max }}</span>
</q-td> </q-td>
<q-td>{{ props.row.currency || 'sat' }}</q-td> <q-td>{{ props.row.currency || 'sat' }}</q-td>
<q-td auto-width :class="(props.row.username) ? 'text-normal' : 'text-grey'">{{ props.row.username || 'None' }}</q-td> <q-td
auto-width
:class="(props.row.username) ? 'text-normal' : 'text-grey'"
>{{ props.row.username || 'None' }}</q-td
>
<q-td> <q-td>
<q-icon v-if="props.row.webhook_url" size="14px" name="http"> <q-icon v-if="props.row.webhook_url" size="14px" name="http">
<q-tooltip>Webhook to {{ props.row.webhook_url}}</q-tooltip> <q-tooltip>Webhook to {{ props.row.webhook_url }}</q-tooltip>
</q-icon> </q-icon>
<q-icon <q-icon
v-if="props.row.success_text || props.row.success_url" v-if="props.row.success_text || props.row.success_url"
@ -111,7 +117,8 @@
@click="deletePayLink(props.row.id)" @click="deletePayLink(props.row.id)"
icon="cancel" icon="cancel"
color="pink" color="pink"
><q-tooltip>Delete</q-tooltip></q-btn> ><q-tooltip>Delete</q-tooltip></q-btn
>
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
@ -125,7 +132,7 @@
<q-card> <q-card>
<q-card-section> <q-card-section>
<h6 class="text-subtitle1 q-my-none"> <h6 class="text-subtitle1 q-my-none">
{{SITE_TITLE}} LNURL-pay extension {{ SITE_TITLE }} LNURL-pay extension
</h6> </h6>
</q-card-section> </q-card-section>
<q-card-section class="q-pa-none"> <q-card-section class="q-pa-none">
@ -167,14 +174,15 @@
v-model.trim="formDialog.data.username" v-model.trim="formDialog.data.username"
type="text" type="text"
label="Lightning Address" label="Lightning Address"
> />
</div> </div>
<div class="col" style="margin-top: 10px"> <div class="col" style="margin-top: 10px">
<span class="label"> &nbsp; @ {% raw %} {{domain}} {% endraw %} </span> <span class="label">
&nbsp; @ {% raw %} {{ domain }} {% endraw %}
</span>
</div> </div>
</q-input>
</div> </div>
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm q-mx-sm">
<q-input <q-input
filled filled
dense dense
@ -209,20 +217,34 @@
v-model="formDialog.data.currency" v-model="formDialog.data.currency"
:display-value="formDialog.data.currency || 'satoshis'" :display-value="formDialog.data.currency || 'satoshis'"
label="Currency" label="Currency"
:hint="'Amounts will be converted at use-time to satoshis. ' + (formDialog.data.currency && fiatRates[formDialog.data.currency] ? `Currently 1 ${formDialog.data.currency} = ${fiatRates[formDialog.data.currency]} sat` : '')" :hint="'Converted to satoshis at each payment. ' + (formDialog.data.currency && fiatRates[formDialog.data.currency] ? `Currently 1 ${formDialog.data.currency} = ${fiatRates[formDialog.data.currency]} sat` : '')"
@input="updateFiatRate" @input="updateFiatRate"
/> />
</div> </div>
</div> </div>
<q-expansion-item
group="advanced"
icon="settings"
label="Advanced options"
>
<q-card>
<q-card-section>
<h5 class="text-caption q-mt-sm q-mb-none">LNURL</h5>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
v-model.number="formDialog.data.comment_chars" v-model.number="formDialog.data.comment_chars"
type="number" type="number"
label="Comment maximum characters" label="Comment maximum characters"
hint="Tell wallets to prompt users for a comment that will be sent along with the payment. LNURLp will store the comment and send it in the webhook." hint="Allow the payer to attach a comment."
> >
</q-input> </q-input>
</div>
</div>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
@ -231,6 +253,10 @@
label="Webhook URL (optional)" label="Webhook URL (optional)"
hint="A URL to be called whenever this link receives a payment." hint="A URL to be called whenever this link receives a payment."
></q-input> ></q-input>
</div>
</div>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
@ -240,6 +266,10 @@
label="Webhook headers (optional)" label="Webhook headers (optional)"
hint="Custom data as JSON string, send headers along with the webhook." hint="Custom data as JSON string, send headers along with the webhook."
></q-input> ></q-input>
</div>
</div>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
@ -249,6 +279,10 @@
label="Webhook custom data (optional)" label="Webhook custom data (optional)"
hint="Custom data as JSON string, will get posted along with webhook 'body' field." hint="Custom data as JSON string, will get posted along with webhook 'body' field."
></q-input> ></q-input>
</div>
</div>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
@ -257,15 +291,37 @@
label="Success message (optional)" label="Success message (optional)"
hint="Will be shown to the user in his wallet after a successful payment." hint="Will be shown to the user in his wallet after a successful payment."
></q-input> ></q-input>
</div>
</div>
<div class="row">
<div class="col-12">
<q-input <q-input
filled filled
dense dense
v-model="formDialog.data.success_url" v-model="formDialog.data.success_url"
type="text" type="text"
label="Success URL (optional)" label="Success URL (optional)"
hint="Will be shown as a clickable link to the user in his wallet after a successful payment, appended by the payment_hash as a query string." hint="Link will be shown to the sender after a successful payment."
> >
</q-input> </q-input>
</div>
</div>
</q-card-section>
<q-card-section>
<h5 class="text-caption q-mt-sm q-mb-none">Nostr</h5>
<div class="row">
<div class="col-12">
<q-checkbox
:toggle-indeterminate="false"
dense
v-model="formDialog.data.zaps"
label="Enable nostr zaps"
/>
</div>
</div>
</q-card-section>
</q-card>
</q-expansion-item>
<div class="row q-mt-lg"> <div class="row q-mt-lg">
<q-btn <q-btn
v-if="formDialog.data.id" v-if="formDialog.data.id"
@ -311,17 +367,22 @@
<strong>ID:</strong> {{ qrCodeDialog.data.id }}<br /> <strong>ID:</strong> {{ qrCodeDialog.data.id }}<br />
<strong>Amount:</strong> {{ qrCodeDialog.data.amount }}<br /> <strong>Amount:</strong> {{ qrCodeDialog.data.amount }}<br />
<span v-if="qrCodeDialog.data.currency" <span v-if="qrCodeDialog.data.currency"
><strong>{{ qrCodeDialog.data.currency }} price:</strong> {{ ><strong>{{ qrCodeDialog.data.currency }} price:</strong>
fiatRates[qrCodeDialog.data.currency] ? {{
fiatRates[qrCodeDialog.data.currency] + ' sat' : 'Loading...' }}<br fiatRates[qrCodeDialog.data.currency]
? fiatRates[qrCodeDialog.data.currency] + ' sat'
: 'Loading...'
}}<br
/></span> /></span>
<strong>Accepts comments:</strong> {{ qrCodeDialog.data.comments }}<br /> <strong>Accepts comments:</strong> {{ qrCodeDialog.data.comments
}}<br />
<strong>Dispatches webhook to:</strong> {{ qrCodeDialog.data.webhook <strong>Dispatches webhook to:</strong> {{ qrCodeDialog.data.webhook
}}<br /> }}<br />
<strong>On success:</strong> {{ qrCodeDialog.data.success }}<br /> <strong>On success:</strong> {{ qrCodeDialog.data.success }}<br />
<span v-if="qrCodeDialog.data.username"> <span v-if="qrCodeDialog.data.username">
<strong>Lightning Address: </strong> {{ qrCodeDialog.data.username}}@{{domain}} <strong>Lightning Address: </strong>
<br/> {{ qrCodeDialog.data.username }}@{{ domain }}
<br />
</span> </span>
</p> </p>
{% endraw %} {% endraw %}