Browse Source

feat(withdraw): type casting

Login
Eneko Illarramendi 5 years ago
parent
commit
14d61eaf56
  1. 8
      lnbits/extensions/withdraw/crud.py
  2. 1
      lnbits/extensions/withdraw/migrations.py
  3. 7
      lnbits/extensions/withdraw/models.py
  4. 1
      lnbits/extensions/withdraw/static/js/index.js
  5. 28
      lnbits/extensions/withdraw/templates/withdraw/_api_docs.html
  6. 5
      lnbits/extensions/withdraw/views_api.py

8
lnbits/extensions/withdraw/crud.py

@ -58,14 +58,14 @@ def get_withdraw_link(link_id: str) -> Optional[WithdrawLink]:
with open_ext_db("withdraw") as db: with open_ext_db("withdraw") as db:
row = db.fetchone("SELECT * FROM withdraw_links WHERE id = ?", (link_id,)) row = db.fetchone("SELECT * FROM withdraw_links WHERE id = ?", (link_id,))
return WithdrawLink(**row) if row else None return WithdrawLink.from_row(row) if row else None
def get_withdraw_link_by_hash(unique_hash: str) -> Optional[WithdrawLink]: def get_withdraw_link_by_hash(unique_hash: str) -> Optional[WithdrawLink]:
with open_ext_db("withdraw") as db: with open_ext_db("withdraw") as db:
row = db.fetchone("SELECT * FROM withdraw_links WHERE unique_hash = ?", (unique_hash,)) row = db.fetchone("SELECT * FROM withdraw_links WHERE unique_hash = ?", (unique_hash,))
return WithdrawLink(**row) if row else None return WithdrawLink.from_row(row) if row else None
def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[WithdrawLink]: def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[WithdrawLink]:
@ -76,7 +76,7 @@ def get_withdraw_links(wallet_ids: Union[str, List[str]]) -> List[WithdrawLink]:
q = ",".join(["?"] * len(wallet_ids)) q = ",".join(["?"] * len(wallet_ids))
rows = db.fetchall(f"SELECT * FROM withdraw_links WHERE wallet IN ({q})", (*wallet_ids,)) rows = db.fetchall(f"SELECT * FROM withdraw_links WHERE wallet IN ({q})", (*wallet_ids,))
return [WithdrawLink(**row) for row in rows] return [WithdrawLink.from_row(row) for row in rows]
def update_withdraw_link(link_id: str, **kwargs) -> Optional[WithdrawLink]: def update_withdraw_link(link_id: str, **kwargs) -> Optional[WithdrawLink]:
@ -86,7 +86,7 @@ def update_withdraw_link(link_id: str, **kwargs) -> Optional[WithdrawLink]:
db.execute(f"UPDATE withdraw_links SET {q} WHERE id = ?", (*kwargs.values(), link_id)) db.execute(f"UPDATE withdraw_links SET {q} WHERE id = ?", (*kwargs.values(), link_id))
row = db.fetchone("SELECT * FROM withdraw_links WHERE id = ?", (link_id,)) row = db.fetchone("SELECT * FROM withdraw_links WHERE id = ?", (link_id,))
return WithdrawLink(**row) if row else None return WithdrawLink.from_row(row) if row else None
def delete_withdraw_link(link_id: str) -> None: def delete_withdraw_link(link_id: str) -> None:

1
lnbits/extensions/withdraw/migrations.py

@ -91,6 +91,7 @@ def m002_change_withdraw_table(db):
row[9], # spent row[9], # spent
), ),
) )
db.execute("DROP TABLE withdraws") db.execute("DROP TABLE withdraws")

7
lnbits/extensions/withdraw/models.py

@ -1,5 +1,6 @@
from flask import url_for from flask import url_for
from lnurl import Lnurl, LnurlWithdrawResponse, encode as lnurl_encode from lnurl import Lnurl, LnurlWithdrawResponse, encode as lnurl_encode
from sqlite3 import Row
from typing import NamedTuple from typing import NamedTuple
from lnbits.settings import FORCE_HTTPS from lnbits.settings import FORCE_HTTPS
@ -19,6 +20,12 @@ class WithdrawLink(NamedTuple):
open_time: int open_time: int
used: int used: int
@classmethod
def from_row(cls, row: Row) -> "WithdrawLink":
data = dict(row)
data["is_unique"] = bool(data["is_unique"])
return cls(**data)
@property @property
def is_spent(self) -> bool: def is_spent(self) -> bool:
return self.used >= self.uses return self.used >= self.uses

1
lnbits/extensions/withdraw/static/js/index.js

@ -3,7 +3,6 @@ Vue.component(VueQrcode.name, VueQrcode);
var locationPath = [window.location.protocol, '//', window.location.hostname, window.location.pathname].join(''); var locationPath = [window.location.protocol, '//', window.location.hostname, window.location.pathname].join('');
var mapWithdrawLink = function (obj) { var mapWithdrawLink = function (obj) {
obj.is_unique = obj.is_unique == 1;
obj._data = _.clone(obj); obj._data = _.clone(obj);
obj.date = Quasar.utils.date.formatDate(new Date(obj.time * 1000), 'YYYY-MM-DD HH:mm'); obj.date = Quasar.utils.date.formatDate(new Date(obj.time * 1000), 'YYYY-MM-DD HH:mm');
obj.min_fsat = new Intl.NumberFormat(LOCALE).format(obj.min_withdrawable); obj.min_fsat = new Intl.NumberFormat(LOCALE).format(obj.min_withdrawable);

28
lnbits/extensions/withdraw/templates/withdraw/_api_docs.html

@ -8,20 +8,20 @@
group="api" group="api"
dense dense
expand-separator expand-separator
label="List all withdraw links" label="List withdraw links"
> >
<q-card> <q-card>
<q-card-section> <q-card-section>
<code <code
><span class="text-light-blue">GET</span> /withdraw/api/v1/links</code ><span class="text-blue">GET</span> /withdraw/api/v1/links</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": &lt;invoice_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;invoice_key&gt;}</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>
<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 200 OK (application/json)
</h5> </h5>
<code>{"lnurl": &lt;string&gt;}</code> <code>[&lt;withdraw_link_object&gt;, ...]</code>
<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 }}withdraw/api/v1/links -H >curl -X GET {{ request.url_root }}withdraw/api/v1/links -H
@ -34,13 +34,13 @@
group="api" group="api"
dense dense
expand-separator expand-separator
label="List specific withdraw link" label="Get a withdraw link"
> >
<q-card> <q-card>
<q-card-section> <q-card-section>
<code <code
><span class="text-light-blue">GET</span> ><span class="text-blue">GET</span>
/withdraw/api/v1/links/&lt;LNURL_id&gt;</code /withdraw/api/v1/links/&lt;withdraw_id&gt;</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": &lt;invoice_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;invoice_key&gt;}</code><br />
@ -52,7 +52,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 >curl -X GET {{ request.url_root
}}withdraw/api/v1/links/&lt;LNURL_id&gt; -H "X-Api-Key: {{ }}withdraw/api/v1/links/&lt;withdraw_id&gt; -H "X-Api-Key: {{
g.user.wallets[0].inkey }}" g.user.wallets[0].inkey }}"
</code> </code>
</q-card-section> </q-card-section>
@ -67,7 +67,7 @@
<q-card> <q-card>
<q-card-section> <q-card-section>
<code <code
><span class="text-light-green">POST</span> ><span class="text-green">POST</span>
/withdraw/api/v1/links</code /withdraw/api/v1/links</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>
@ -103,7 +103,7 @@
<q-card> <q-card>
<q-card-section> <q-card-section>
<code <code
><span class="text-light-blue">PUT</span> ><span class="text-green">PUT</span>
/withdraw/api/v1/links/&lt;withdraw_id&gt;</code /withdraw/api/v1/links/&lt;withdraw_id&gt;</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>
@ -115,7 +115,7 @@
"wait_time": &lt;integer&gt;, "is_unique": &lt;boolean&gt;}</code "wait_time": &lt;integer&gt;, "is_unique": &lt;boolean&gt;}</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 200 OK (application/json)
</h5> </h5>
<code>{"lnurl": &lt;string&gt;}</code> <code>{"lnurl": &lt;string&gt;}</code>
<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>
@ -141,13 +141,13 @@
<q-card> <q-card>
<q-card-section> <q-card-section>
<code <code
><span class="text-light-green">DELETE</span> ><span class="text-pink">DELETE</span>
/withdraw/api/v1/links/&lt;withdraw_id&gt;</code /withdraw/api/v1/links/&lt;withdraw_id&gt;</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": &lt;admin_key&gt;}</code><br /> <code>{"X-Api-Key": &lt;admin_key&gt;}</code><br />
<h5 class="text-caption q-mt-sm q-mb-none">Returns 201 NO_CONTENT</h5> <h5 class="text-caption q-mt-sm q-mb-none">Returns 204 NO CONTENT</h5>
<code>{"lnurl": &lt;string&gt;}</code> <code></code>
<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 >curl -X DELETE {{ request.url_root

5
lnbits/extensions/withdraw/views_api.py

@ -68,7 +68,10 @@ def api_link_retrieve(link_id):
) )
def api_link_create_or_update(link_id=None): def api_link_create_or_update(link_id=None):
if g.data["max_withdrawable"] < g.data["min_withdrawable"]: if g.data["max_withdrawable"] < g.data["min_withdrawable"]:
return jsonify({"message": "`max_withdrawable` needs to be at least `min_withdrawable`."}), HTTPStatus.BAD_REQUEST return (
jsonify({"message": "`max_withdrawable` needs to be at least `min_withdrawable`."}),
HTTPStatus.BAD_REQUEST,
)
if (g.data["max_withdrawable"] * g.data["uses"] * 1000) > g.wallet.balance_msat: if (g.data["max_withdrawable"] * g.data["uses"] * 1000) > g.wallet.balance_msat:
return jsonify({"message": "Insufficient balance."}), HTTPStatus.FORBIDDEN return jsonify({"message": "Insufficient balance."}), HTTPStatus.FORBIDDEN

Loading…
Cancel
Save