Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update to lnbits 1.0.0 #53

Merged
merged 19 commits into from
Nov 12, 2024
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Withdraw Links",
"short_description": "Make LNURL withdraw links",
"tile": "/withdraw/static/image/lnurl-withdraw.png",
"min_lnbits_version": "0.12.11",
"min_lnbits_version": "1.0.0",
"contributors": [
{
"name": "arcbtc",
Expand Down
192 changes: 77 additions & 115 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from datetime import datetime
from time import time
from typing import List, Optional, Tuple
from typing import Optional

import shortuuid
from lnbits.db import Database
Expand All @@ -16,107 +15,80 @@ async def create_withdraw_link(
) -> WithdrawLink:
link_id = urlsafe_short_hash()[:22]
available_links = ",".join([str(i) for i in range(data.uses)])
await db.execute(
f"""
INSERT INTO withdraw.withdraw_link (
id,
wallet,
title,
min_withdrawable,
max_withdrawable,
uses,
wait_time,
is_unique,
unique_hash,
k1,
open_time,
usescsv,
webhook_url,
webhook_headers,
webhook_body,
custom_url,
created_at
)
VALUES
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, {db.timestamp_placeholder})
""",
(
link_id,
wallet_id,
data.title,
data.min_withdrawable,
data.max_withdrawable,
data.uses,
data.wait_time,
int(data.is_unique),
urlsafe_short_hash(),
urlsafe_short_hash(),
int(datetime.now().timestamp()) + data.wait_time,
available_links,
data.webhook_url,
data.webhook_headers,
data.webhook_body,
data.custom_url,
int(time()),
),
withdraw_link = WithdrawLink(
id=link_id,
wallet=wallet_id,
unique_hash=urlsafe_short_hash(),
k1=urlsafe_short_hash(),
created_at=datetime.now(),
open_time=int(datetime.now().timestamp()) + data.wait_time,
title=data.title,
min_withdrawable=data.min_withdrawable,
max_withdrawable=data.max_withdrawable,
uses=data.uses,
wait_time=data.wait_time,
is_unique=data.is_unique,
usescsv=available_links,
webhook_url=data.webhook_url,
webhook_headers=data.webhook_headers,
webhook_body=data.webhook_body,
custom_url=data.custom_url,
number=0,
)
link = await get_withdraw_link(link_id, 0)
assert link, "Newly created link couldn't be retrieved"
return link
await db.insert("withdraw.withdraw_link", withdraw_link) # type: ignore
return withdraw_link


async def get_withdraw_link(link_id: str, num=0) -> Optional[WithdrawLink]:
row = await db.fetchone(
"SELECT * FROM withdraw.withdraw_link WHERE id = ?", (link_id,)
link: WithdrawLink = await db.fetchone(
"SELECT * FROM withdraw.withdraw_link WHERE id = :id",
{"id": link_id},
WithdrawLink,
)
if not row:
if not link:
return None

link = dict(**row)
link["number"] = num

return WithdrawLink.parse_obj(link)
link.number = num
return link


async def get_withdraw_link_by_hash(unique_hash: str, num=0) -> Optional[WithdrawLink]:
row = await db.fetchone(
"SELECT * FROM withdraw.withdraw_link WHERE unique_hash = ?", (unique_hash,)
link = await db.fetchone(
"SELECT * FROM withdraw.withdraw_link WHERE unique_hash = :hash",
{"hash": unique_hash},
WithdrawLink,
)
if not row:
if not link:
return None

link = dict(**row)
link["number"] = num
if not link:
return None

return WithdrawLink.parse_obj(link)
link.number = num
return link


async def get_withdraw_links(
wallet_ids: List[str], limit: int, offset: int
) -> Tuple[List[WithdrawLink], int]:
rows = await db.fetchall(
"""
SELECT * FROM withdraw.withdraw_link
WHERE wallet IN ({})
ORDER BY open_time DESC
LIMIT ? OFFSET ?
""".format(
",".join("?" * len(wallet_ids))
),
(*wallet_ids, limit, offset),
wallet_ids: list[str], limit: int, offset: int
) -> tuple[list[WithdrawLink], int]:
q = ",".join([f"'{w}'" for w in wallet_ids])
links = await db.fetchall(
f"""
SELECT * FROM withdraw.withdraw_link WHERE wallet IN ({q})
ORDER BY open_time DESC LIMIT :limit OFFSET :offset
""",
{"limit": limit, "offset": offset},
WithdrawLink,
)

total = await db.fetchone(
"""
f"""
SELECT COUNT(*) as total FROM withdraw.withdraw_link
WHERE wallet IN ({})
""".format(
",".join("?" * len(wallet_ids))
),
(*wallet_ids,),
WHERE wallet IN ({q})
"""
)

return [WithdrawLink(**row) for row in rows], total["total"]
return links, total["total"]


async def remove_unique_withdraw_link(link: WithdrawLink, unique_hash: str) -> None:
Expand All @@ -125,36 +97,25 @@ async def remove_unique_withdraw_link(link: WithdrawLink, unique_hash: str) -> N
for x in link.usescsv.split(",")
if unique_hash != shortuuid.uuid(name=link.id + link.unique_hash + x.strip())
]
await update_withdraw_link(
link.id,
usescsv=",".join(unique_links),
)
link.usescsv = ",".join(unique_links)
await update_withdraw_link(link)


async def increment_withdraw_link(link: WithdrawLink) -> None:
await update_withdraw_link(
link.id,
used=link.used + 1,
open_time=link.wait_time + int(datetime.now().timestamp()),
)
link.used = link.used + 1
link.open_time = int(datetime.now().timestamp()) + link.wait_time
await update_withdraw_link(link)


async def update_withdraw_link(link_id: str, **kwargs) -> Optional[WithdrawLink]:
if "is_unique" in kwargs:
kwargs["is_unique"] = int(kwargs["is_unique"])
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
await db.execute(
f"UPDATE withdraw.withdraw_link SET {q} WHERE id = ?",
(*kwargs.values(), link_id),
)
row = await db.fetchone(
"SELECT * FROM withdraw.withdraw_link WHERE id = ?", (link_id,)
)
return WithdrawLink(**row) if row else None
async def update_withdraw_link(link: WithdrawLink) -> WithdrawLink:
await db.update("withdraw.withdraw_link", link) # type: ignore
return link


async def delete_withdraw_link(link_id: str) -> None:
await db.execute("DELETE FROM withdraw.withdraw_link WHERE id = ?", (link_id,))
await db.execute(
"DELETE FROM withdraw.withdraw_link WHERE id = :id", {"id": link_id}
)


def chunks(lst, n):
Expand All @@ -165,35 +126,36 @@ def chunks(lst, n):
async def create_hash_check(the_hash: str, lnurl_id: str) -> HashCheck:
await db.execute(
"""
INSERT INTO withdraw.hash_check (
id,
lnurl_id
)
VALUES (?, ?)
INSERT INTO withdraw.hash_check (id, lnurl_id)
VALUES (:id, :lnurl_id)
""",
(the_hash, lnurl_id),
{"id": the_hash, "lnurl_id": lnurl_id},
)
hash_check = await get_hash_check(the_hash, lnurl_id)
return hash_check


async def get_hash_check(the_hash: str, lnurl_id: str) -> HashCheck:
rowid = await db.fetchone(
"SELECT * FROM withdraw.hash_check WHERE id = ?", (the_hash,)
hash_check = await db.fetchone(
"SELECT * FROM withdraw.hash_check WHERE id = :id", {"id": the_hash}, HashCheck
)
rowlnurl = await db.fetchone(
"SELECT * FROM withdraw.hash_check WHERE lnurl_id = ?", (lnurl_id,)
hash_check_lnurl = await db.fetchone(
"SELECT * FROM withdraw.hash_check WHERE lnurl_id = :id",
{"id": lnurl_id},
HashCheck,
)
if not rowlnurl:
if not hash_check_lnurl:
await create_hash_check(the_hash, lnurl_id)
return HashCheck(lnurl=True, hash=False)
else:
if not rowid:
if not hash_check:
await create_hash_check(the_hash, lnurl_id)
return HashCheck(lnurl=True, hash=False)
else:
return HashCheck(lnurl=True, hash=True)


async def delete_hash_check(the_hash: str) -> None:
await db.execute("DELETE FROM withdraw.hash_check WHERE id = ?", (the_hash,))
await db.execute(
"DELETE FROM withdraw.hash_check WHERE id = :hash", {"hash": the_hash}
)
4 changes: 2 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
MilliSatoshi, # type: ignore
)
from lnurl import encode as lnurl_encode
from pydantic import BaseModel
from pydantic import BaseModel, Field


class CreateWithdrawData(BaseModel):
Expand Down Expand Up @@ -42,7 +42,7 @@ class WithdrawLink(BaseModel):
open_time: int = Query(0)
used: int = Query(0)
usescsv: str = Query(None)
number: int = Query(0)
number: int = Field(default=0, no_database=True)
webhook_url: str = Query(None)
webhook_headers: str = Query(None)
webhook_body: str = Query(None)
Expand Down
Loading
Loading