mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-21 22:11:59 +01:00
feat(paywall): improved extension
- make remember cookie optional - improve database - improve type casting
This commit is contained in:
parent
2fac47c05a
commit
e73a508011
8 changed files with 319 additions and 78 deletions
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "Paywall",
|
||||
"short_description": "Create paywalls for content",
|
||||
"icon": "vpn_lock",
|
||||
"icon": "policy",
|
||||
"contributors": ["eillarra"]
|
||||
}
|
||||
|
|
|
@ -6,15 +6,17 @@ from lnbits.helpers import urlsafe_short_hash
|
|||
from .models import Paywall
|
||||
|
||||
|
||||
def create_paywall(*, wallet_id: str, url: str, memo: str, amount: int) -> Paywall:
|
||||
def create_paywall(
|
||||
*, wallet_id: str, url: str, memo: str, description: Optional[str] = None, amount: int = 0, remembers: bool = True
|
||||
) -> Paywall:
|
||||
with open_ext_db("paywall") as db:
|
||||
paywall_id = urlsafe_short_hash()
|
||||
db.execute(
|
||||
"""
|
||||
INSERT INTO paywalls (id, wallet, secret, url, memo, amount)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO paywalls (id, wallet, url, memo, description, amount, remembers)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(paywall_id, wallet_id, urlsafe_short_hash(), url, memo, amount),
|
||||
(paywall_id, wallet_id, url, memo, description, amount, int(remembers)),
|
||||
)
|
||||
|
||||
return get_paywall(paywall_id)
|
||||
|
@ -24,7 +26,7 @@ def get_paywall(paywall_id: str) -> Optional[Paywall]:
|
|||
with open_ext_db("paywall") as db:
|
||||
row = db.fetchone("SELECT * FROM paywalls WHERE id = ?", (paywall_id,))
|
||||
|
||||
return Paywall(**row) if row else None
|
||||
return Paywall.from_row(row) if row else None
|
||||
|
||||
|
||||
def get_paywalls(wallet_ids: Union[str, List[str]]) -> List[Paywall]:
|
||||
|
@ -35,7 +37,7 @@ def get_paywalls(wallet_ids: Union[str, List[str]]) -> List[Paywall]:
|
|||
q = ",".join(["?"] * len(wallet_ids))
|
||||
rows = db.fetchall(f"SELECT * FROM paywalls WHERE wallet IN ({q})", (*wallet_ids,))
|
||||
|
||||
return [Paywall(**row) for row in rows]
|
||||
return [Paywall.from_row(row) for row in rows]
|
||||
|
||||
|
||||
def delete_paywall(paywall_id: str) -> None:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from sqlite3 import OperationalError
|
||||
|
||||
from lnbits.db import open_ext_db
|
||||
|
||||
|
||||
|
@ -20,6 +22,52 @@ def m001_initial(db):
|
|||
)
|
||||
|
||||
|
||||
def m002_redux(db):
|
||||
"""
|
||||
Creates an improved paywalls table and migrates the existing data.
|
||||
"""
|
||||
try:
|
||||
db.execute("SELECT remembers FROM paywalls")
|
||||
|
||||
except OperationalError:
|
||||
db.execute("ALTER TABLE paywalls RENAME TO paywalls_old")
|
||||
db.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS paywalls (
|
||||
id TEXT PRIMARY KEY,
|
||||
wallet TEXT NOT NULL,
|
||||
url TEXT NOT NULL,
|
||||
memo TEXT NOT NULL,
|
||||
description TEXT NULL,
|
||||
amount INTEGER DEFAULT 0,
|
||||
time TIMESTAMP NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
remembers INTEGER DEFAULT 0,
|
||||
extras TEXT NULL
|
||||
);
|
||||
"""
|
||||
)
|
||||
db.execute("CREATE INDEX IF NOT EXISTS wallet_idx ON paywalls (wallet)")
|
||||
|
||||
for row in [list(row) for row in db.fetchall("SELECT * FROM paywalls_old")]:
|
||||
db.execute(
|
||||
"""
|
||||
INSERT INTO paywalls (
|
||||
id,
|
||||
wallet,
|
||||
url,
|
||||
memo,
|
||||
amount,
|
||||
time
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(row[0], row[1], row[3], row[4], row[5], row[6]),
|
||||
)
|
||||
|
||||
db.execute("DROP TABLE paywalls_old")
|
||||
|
||||
|
||||
def migrate():
|
||||
with open_ext_db("paywall") as db:
|
||||
m001_initial(db)
|
||||
m002_redux(db)
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
from typing import NamedTuple
|
||||
import json
|
||||
|
||||
from sqlite3 import Row
|
||||
from typing import NamedTuple, Optional
|
||||
|
||||
|
||||
class Paywall(NamedTuple):
|
||||
id: str
|
||||
wallet: str
|
||||
secret: str
|
||||
url: str
|
||||
memo: str
|
||||
description: str
|
||||
amount: int
|
||||
time: int
|
||||
remembers: bool
|
||||
extras: Optional[dict]
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: Row) -> "Paywall":
|
||||
data = dict(row)
|
||||
data["remembers"] = bool(data["remembers"])
|
||||
data["extras"] = json.loads(data["extras"]) if data["extras"] else None
|
||||
return cls(**data)
|
||||
|
|
|
@ -6,12 +6,106 @@
|
|||
>
|
||||
<q-expansion-item group="api" dense expand-separator label="List paywalls">
|
||||
<q-card>
|
||||
<q-card-section> </q-card-section>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-blue">GET</span> /paywall/api/v1/paywalls</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <invoice_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">
|
||||
Returns 200 OK (application/json)
|
||||
</h5>
|
||||
<code>[<paywall_object>, ...]</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X GET {{ request.url_root }}paywall/api/v1/paywalls -H
|
||||
"X-Api-Key: {{ g.user.wallets[0].inkey }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item group="api" dense expand-separator label="Create a paywall">
|
||||
<q-card>
|
||||
<q-card-section> </q-card-section>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-green">POST</span>
|
||||
/paywall/api/v1/paywalls</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<code
|
||||
>{"amount": <integer>, "description": <string>,
|
||||
"memo": <string>, "remembers": <boolean>,
|
||||
"url": <string>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 201 CREATED (application/json)
|
||||
</h5>
|
||||
<code>{"amount": <integer>, "description": <string>,
|
||||
"id": <string>, "memo": <string>,
|
||||
"remembers": <boolean>, "time": <int>,
|
||||
"url": <string>, "wallet": <string>}</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X POST {{ request.url_root }}paywall/api/v1/paywalls -d
|
||||
'{"url": <string>, "memo": <string>,
|
||||
"description": <string>, "amount": <integer>,
|
||||
"remembers": <boolean>}' -H
|
||||
"Content-type: application/json" -H "X-Api-Key: {{
|
||||
g.user.wallets[0].adminkey }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item group="api" dense expand-separator label="Create an invoice (public)">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-green">POST</span>
|
||||
/paywall/api/v1/paywalls/<paywall_id>/invoice</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<code
|
||||
>{"amount": <integer>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 201 CREATED (application/json)
|
||||
</h5>
|
||||
<code>{"checking_id": <string>, "payment_request": <string>}</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X POST {{ request.url_root }}paywall/api/v1/paywalls/<paywall_id>/invoice -d
|
||||
'{"amount": <integer>}' -H
|
||||
"Content-type: application/json"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item group="api" dense expand-separator label="Check invoice status (public)">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-green">POST</span>
|
||||
/paywall/api/v1/paywalls/<paywall_id>/check_invoice</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<code
|
||||
>{"checking_id": <string>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 200 OK (application/json)
|
||||
</h5>
|
||||
<code>{"paid": false}</code><br>
|
||||
<code>{"paid": true, "url": <string>, "remembers": <boolean>}</code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X POST {{ request.url_root }}paywall/api/v1/paywalls/<paywall_id>/check_invoice -d
|
||||
'{"checking_id": <string>}' -H
|
||||
"Content-type: application/json"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
<q-expansion-item
|
||||
|
@ -22,7 +116,22 @@
|
|||
class="q-pb-md"
|
||||
>
|
||||
<q-card>
|
||||
<q-card-section> </q-card-section>
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-pink">DELETE</span>
|
||||
/paywall/api/v1/paywalls/<paywall_id></code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <admin_key>}</code><br />
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Returns 204 NO CONTENT</h5>
|
||||
<code></code>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Curl example</h5>
|
||||
<code
|
||||
>curl -X DELETE {{ request.url_root
|
||||
}}paywall/api/v1/paywalls/<paywall_id> -H "X-Api-Key: {{
|
||||
g.user.wallets[0].adminkey }}"
|
||||
</code>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
</q-expansion-item>
|
||||
|
|
|
@ -1,31 +1,48 @@
|
|||
{% extends "public.html" %} {% block page %}
|
||||
<div class="row q-col-gutter-md justify-center">
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-4">
|
||||
<div class="col-12 col-sm-8 col-md-5 col-lg-4">
|
||||
<q-card class="q-pa-lg">
|
||||
<q-card-section class="q-pa-none">
|
||||
<h5 class="text-subtitle1 q-my-none">{{ paywall.memo }}</h5>
|
||||
<strong class="text-purple"
|
||||
>Price:
|
||||
<lnbits-fsat :amount="{{ paywall.amount }}"></lnbits-fsat> sat</strong
|
||||
>
|
||||
<q-separator class="q-my-lg"></q-separator>
|
||||
<div v-if="paymentReq">
|
||||
<a :href="'lightning:' + paymentReq">
|
||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||
<qrcode
|
||||
:value="paymentReq"
|
||||
:options="{width: 800}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
</q-responsive>
|
||||
</a>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn outline color="grey" @click="copyText(paymentReq)"
|
||||
>Copy invoice</q-btn
|
||||
<h5 class="text-subtitle1 q-mt-none q-mb-sm">{{ paywall.memo }}</h5>
|
||||
{% if paywall.description %}
|
||||
<p>{{ paywall.description }}</p>
|
||||
{% endif %}
|
||||
<div v-if="!this.redirectUrl" class="q-mt-lg">
|
||||
<q-form v-if="">
|
||||
<q-input
|
||||
filled
|
||||
v-model.number="userAmount"
|
||||
type="number"
|
||||
:min="paywallAmount"
|
||||
suffix="sat"
|
||||
label="Choose an amount *"
|
||||
:hint="'Minimum ' + paywallAmount + ' sat'"
|
||||
>
|
||||
<template v-slot:after>
|
||||
<q-btn round dense flat icon="check" color="deep-purple" type="submit" @click="createInvoice" :disabled="userAmount < paywallAmount"></q-btn>
|
||||
</template>
|
||||
</q-input>
|
||||
</q-form>
|
||||
<div v-if="paymentReq" class="q-mt-lg">
|
||||
<a :href="'lightning:' + paymentReq">
|
||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||
<qrcode
|
||||
:value="paymentReq"
|
||||
:options="{width: 800}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
</q-responsive>
|
||||
</a>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn outline color="grey" @click="copyText(paymentReq)"
|
||||
>Copy invoice</q-btn
|
||||
>
|
||||
<q-btn @click="cancelPayment" flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="redirectUrl">
|
||||
<div v-else>
|
||||
<q-separator class="q-my-lg"></q-separator>
|
||||
<p>
|
||||
You can access the URL behind this paywall:<br />
|
||||
<strong>{% raw %}{{ redirectUrl }}{% endraw %}</strong>
|
||||
|
@ -39,13 +56,6 @@
|
|||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6 col-md-5 col-lg-4 q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-card-section>
|
||||
<h6 class="text-subtitle1 q-mb-sm q-mt-none">LNbits paywall</h6>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %} {% block scripts %}
|
||||
<script src="{{ url_for('static', filename='vendor/vue-qrcode@1.0.2/vue-qrcode.min.js') }}"></script>
|
||||
|
@ -57,25 +67,46 @@
|
|||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {
|
||||
userAmount: {{ paywall.amount }},
|
||||
paywallAmount: {{ paywall.amount }},
|
||||
paymentReq: null,
|
||||
redirectUrl: null
|
||||
redirectUrl: null,
|
||||
paymentDialog: {
|
||||
dismissMsg: null,
|
||||
checker: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
amount: function () {
|
||||
return (this.paywallAmount > this.userAmount) ? this.paywallAmount : this.userAmount
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getInvoice: function () {
|
||||
cancelPayment: function () {
|
||||
this.paymentReq = null
|
||||
clearInterval(this.paymentDialog.checker)
|
||||
if (this.paymentDialog.dismissMsg) {
|
||||
this.paymentDialog.dismissMsg()
|
||||
}
|
||||
},
|
||||
createInvoice: function () {
|
||||
var self = this
|
||||
|
||||
axios
|
||||
.get('/paywall/api/v1/paywalls/{{ paywall.id }}/invoice')
|
||||
.post(
|
||||
'/paywall/api/v1/paywalls/{{ paywall.id }}/invoice',
|
||||
{amount: this.amount}
|
||||
)
|
||||
.then(function (response) {
|
||||
self.paymentReq = response.data.payment_request
|
||||
self.paymentReq = response.data.payment_request.toUpperCase()
|
||||
|
||||
dismissMsg = self.$q.notify({
|
||||
self.paymentDialog.dismissMsg = self.$q.notify({
|
||||
timeout: 0,
|
||||
message: 'Waiting for payment...'
|
||||
})
|
||||
|
||||
paymentChecker = setInterval(function () {
|
||||
self.paymentDialog.checker = setInterval(function () {
|
||||
axios
|
||||
.post(
|
||||
'/paywall/api/v1/paywalls/{{ paywall.id }}/check_invoice',
|
||||
|
@ -83,13 +114,14 @@
|
|||
)
|
||||
.then(function (res) {
|
||||
if (res.data.paid) {
|
||||
clearInterval(paymentChecker)
|
||||
dismissMsg()
|
||||
self.cancelPayment()
|
||||
self.redirectUrl = res.data.url
|
||||
self.$q.localStorage.set(
|
||||
'lnbits.paywall.{{ paywall.id }}',
|
||||
res.data.url
|
||||
)
|
||||
if (res.data.remembers) {
|
||||
self.$q.localStorage.set(
|
||||
'lnbits.paywall.{{ paywall.id }}',
|
||||
res.data.url
|
||||
)
|
||||
}
|
||||
|
||||
self.$q.notify({
|
||||
type: 'positive',
|
||||
|
@ -113,8 +145,6 @@
|
|||
|
||||
if (url) {
|
||||
this.redirectUrl = url
|
||||
} else {
|
||||
this.getInvoice()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -114,7 +114,21 @@
|
|||
dense
|
||||
v-model.trim="formDialog.data.url"
|
||||
type="url"
|
||||
label="Target URL *"
|
||||
label="Redirect URL *"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="formDialog.data.memo"
|
||||
label="Title *"
|
||||
placeholder="LNbits paywall"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
autogrow
|
||||
v-model.trim="formDialog.data.description"
|
||||
label="Description"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
|
@ -122,19 +136,31 @@
|
|||
v-model.number="formDialog.data.amount"
|
||||
type="number"
|
||||
label="Amount (sat) *"
|
||||
hint="This is the minimum amount users can pay/donate."
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="formDialog.data.memo"
|
||||
label="Memo"
|
||||
placeholder="LNbits invoice"
|
||||
></q-input>
|
||||
<q-list>
|
||||
<q-item tag="label" class="rounded-borders">
|
||||
<q-item-section avatar>
|
||||
<q-checkbox
|
||||
v-model="formDialog.data.remembers"
|
||||
color="deep-purple"
|
||||
></q-checkbox>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
>Remember payments</q-item-label
|
||||
>
|
||||
<q-item-label caption
|
||||
>A succesful payment will be registered in the browser's storage, so the user doesn't need to pay again to access the URL.</q-item-label
|
||||
>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="deep-purple"
|
||||
:disable="formDialog.data.amount == null || formDialog.data.amount < 0 || formDialog.data.url == null"
|
||||
:disable="formDialog.data.amount == null || formDialog.data.amount < 0 || formDialog.data.url == null || formDialog.data.memo == null"
|
||||
type="submit"
|
||||
>Create paywall</q-btn
|
||||
>
|
||||
|
@ -168,13 +194,6 @@
|
|||
columns: [
|
||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
||||
{name: 'memo', align: 'left', label: 'Memo', field: 'memo'},
|
||||
{
|
||||
name: 'date',
|
||||
align: 'left',
|
||||
label: 'Date',
|
||||
field: 'date',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
align: 'right',
|
||||
|
@ -184,6 +203,14 @@
|
|||
sort: function (a, b, rowA, rowB) {
|
||||
return rowA.amount - rowB.amount
|
||||
}
|
||||
},
|
||||
{name: 'remembers', align: 'left', label: 'Remember', field: 'remembers'},
|
||||
{
|
||||
name: 'date',
|
||||
align: 'left',
|
||||
label: 'Date',
|
||||
field: 'date',
|
||||
sortable: true
|
||||
}
|
||||
],
|
||||
pagination: {
|
||||
|
@ -192,7 +219,9 @@
|
|||
},
|
||||
formDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
data: {
|
||||
remembers: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -216,7 +245,9 @@
|
|||
var data = {
|
||||
url: this.formDialog.data.url,
|
||||
memo: this.formDialog.data.memo,
|
||||
amount: this.formDialog.data.amount
|
||||
amount: this.formDialog.data.amount,
|
||||
description: this.formDialog.data.description,
|
||||
remembers: this.formDialog.data.remembers
|
||||
}
|
||||
var self = this
|
||||
|
||||
|
@ -231,7 +262,9 @@
|
|||
.then(function (response) {
|
||||
self.paywalls.push(mapPaywall(response.data))
|
||||
self.formDialog.show = false
|
||||
self.formDialog.data = {}
|
||||
self.formDialog.data = {
|
||||
remembers: false
|
||||
}
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
|
|
|
@ -27,7 +27,9 @@ def api_paywalls():
|
|||
schema={
|
||||
"url": {"type": "string", "empty": False, "required": True},
|
||||
"memo": {"type": "string", "empty": False, "required": True},
|
||||
"description": {"type": "string", "empty": True, "nullable": True, "required": False},
|
||||
"amount": {"type": "integer", "min": 0, "required": True},
|
||||
"remembers": {"type": "boolean", "required": True},
|
||||
}
|
||||
)
|
||||
def api_paywall_create():
|
||||
|
@ -52,18 +54,23 @@ def api_paywall_delete(paywall_id):
|
|||
return "", HTTPStatus.NO_CONTENT
|
||||
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>/invoice", methods=["GET"])
|
||||
def api_paywall_get_invoice(paywall_id):
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>/invoice", methods=["POST"])
|
||||
@api_validate_post_request(schema={"amount": {"type": "integer", "min": 1, "required": True}})
|
||||
def api_paywall_create_invoice(paywall_id):
|
||||
paywall = get_paywall(paywall_id)
|
||||
|
||||
if g.data["amount"] < paywall.amount:
|
||||
return jsonify({"message": f"Minimum amount is {paywall.amount} sat."}), HTTPStatus.BAD_REQUEST
|
||||
|
||||
try:
|
||||
amount = g.data["amount"] if g.data["amount"] > paywall.amount else paywall.amount
|
||||
checking_id, payment_request = create_invoice(
|
||||
wallet_id=paywall.wallet, amount=paywall.amount, memo=f"#paywall {paywall.memo}"
|
||||
wallet_id=paywall.wallet, amount=amount, memo=f"#paywall {paywall.memo}"
|
||||
)
|
||||
except Exception as e:
|
||||
return jsonify({"message": str(e)}), HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
|
||||
return jsonify({"checking_id": checking_id, "payment_request": payment_request}), HTTPStatus.OK
|
||||
return jsonify({"checking_id": checking_id, "payment_request": payment_request}), HTTPStatus.CREATED
|
||||
|
||||
|
||||
@paywall_ext.route("/api/v1/paywalls/<paywall_id>/check_invoice", methods=["POST"])
|
||||
|
@ -84,6 +91,6 @@ def api_paywal_check_invoice(paywall_id):
|
|||
payment = wallet.get_payment(g.data["checking_id"])
|
||||
payment.set_pending(False)
|
||||
|
||||
return jsonify({"paid": True, "url": paywall.url}), HTTPStatus.OK
|
||||
return jsonify({"paid": True, "url": paywall.url, "remembers": paywall.remembers}), HTTPStatus.OK
|
||||
|
||||
return jsonify({"paid": False}), HTTPStatus.OK
|
||||
|
|
Loading…
Add table
Reference in a new issue