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

update: to LNbits 1.0.0 #99

Merged
merged 19 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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": "TPoS",
"short_description": "A shareable PoS terminal!",
"tile": "/tpos/static/image/tpos.png",
"min_lnbits_version": "0.12.11",
"min_lnbits_version": "1.0.0",
"contributors": [
{
"name": "Ben Arc",
Expand Down
163 changes: 41 additions & 122 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,168 +1,87 @@
from typing import List, Optional, Union
from time import time
from typing import Optional, Union

from lnbits.db import Database
from lnbits.helpers import urlsafe_short_hash
from loguru import logger

from .models import CreateTposData, LNURLCharge, TPoS, TPoSClean
from .models import CreateTposData, LnurlCharge, Tpos, TposClean

db = Database("ext_tpos")


async def get_current_timestamp():
# Get current DB timestamp
timestamp_query = f"SELECT {db.timestamp_now}"
if db.type in {"POSTGRES", "COCKROACH"}:
timestamp_query = f"SELECT EXTRACT(EPOCH FROM {db.timestamp_now})"
current_timestamp = (await db.fetchone(timestamp_query))[0]
return int(current_timestamp)


async def create_tpos(wallet_id: str, data: CreateTposData) -> TPoS:
async def create_tpos(data: CreateTposData) -> Tpos:
tpos_id = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO tpos.pos
(
id, wallet, name, currency, tip_options, tip_wallet, withdrawlimit,
withdrawpin, withdrawamt, withdrawtime, withdrawbtwn, withdrawtimeopt,
withdrawpindisabled, withdrawpremium
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
tpos_id,
wallet_id,
data.name,
data.currency,
data.tip_options,
data.tip_wallet,
data.withdrawlimit,
data.withdrawpin,
0,
0,
data.withdrawbtwn,
data.withdrawtimeopt,
data.withdrawpindisabled,
data.withdrawpremium,
),
)
tpos = await get_tpos(tpos_id)
assert tpos, "Newly created tpos couldn't be retrieved"
tpos = Tpos(id=tpos_id, **data.dict())
await db.insert("tpos.pos", tpos)
return tpos


async def get_tpos(tpos_id: str) -> Optional[TPoS]:
row = await db.fetchone("SELECT * FROM tpos.pos WHERE id = ?", (tpos_id,))
return TPoS(**row) if row else None

async def get_tpos(tpos_id: str) -> Optional[Tpos]:
return await db.fetchone(
"SELECT * FROM tpos.pos WHERE id = :id", {"id": tpos_id}, Tpos
)

async def start_lnurlcharge(tpos_id: str):
tpos = await get_tpos(tpos_id)
assert tpos, f"TPoS with {tpos_id} not found!"

now = await get_current_timestamp()
withdraw_time_seconds = (
tpos.withdrawbtwn * 60 if tpos.withdrawtimeopt != "secs" else tpos.withdrawbtwn
async def start_lnurlcharge(tpos: Tpos) -> LnurlCharge:
now = int(time())
seconds = (
tpos.withdraw_between * 60
if tpos.withdraw_time_option != "secs"
else tpos.withdraw_between
)
last_withdraw = tpos.withdraw_time - now
assert (
now - tpos.withdrawtime > withdraw_time_seconds
last_withdraw < seconds
), f"""
Last withdraw was made too recently, please try again in
{int(withdraw_time_seconds - (now - tpos.withdrawtime))} secs
Last withdraw was made too recently, please try again in
{int(seconds - (last_withdraw))} secs
"""

token = urlsafe_short_hash()
await db.execute(
"""
INSERT INTO tpos.withdraws (id, tpos_id)
VALUES (?, ?)
VALUES (:id, :tpos_id)
""",
(token, tpos_id),
{"id": token, "tpos_id": tpos.id},
)
lnurlcharge = await get_lnurlcharge(token)
assert lnurlcharge, "Newly created lnurlcharge couldn't be retrieved"
return lnurlcharge


async def get_lnurlcharge(lnurlcharge_id: str) -> Optional[LNURLCharge]:
row = await db.fetchone(
"SELECT * FROM tpos.withdraws WHERE id = ?", (lnurlcharge_id,)
async def get_lnurlcharge(lnurlcharge_id: str) -> Optional[LnurlCharge]:
return await db.fetchone(
"SELECT * FROM tpos.withdraws WHERE id = :id",
{"id": lnurlcharge_id},
LnurlCharge,
)
return LNURLCharge(**row) if row else None


async def update_lnurlcharge(data: LNURLCharge) -> LNURLCharge:
# Construct the SET clause for the SQL query
set_clause = ", ".join([f"{field[0]} = ?" for field in data.dict().items()])

# Get the values for the SET clause
set_values = list(data.dict().values())
set_values.append(data.id) # Add the ID for the WHERE clause

# Execute the UPDATE statement
await db.execute(
f"UPDATE tpos.withdraws SET {set_clause} WHERE id = ?", tuple(set_values)
)

lnurlcharge = await get_lnurlcharge(data.id)
assert lnurlcharge, "Withdraw couldn't be retrieved"

return lnurlcharge


async def get_clean_tpos(tpos_id: str) -> Optional[TPoSClean]:
row = await db.fetchone("SELECT * FROM tpos.pos WHERE id = ?", (tpos_id,))
return TPoSClean(**row) if row else None
async def update_lnurlcharge(charge: LnurlCharge) -> LnurlCharge:
await db.update("tpos.withdraws", charge)
return charge


async def update_tpos_withdraw(data: TPoS, tpos_id: str) -> TPoS:
# Calculate the time between withdrawals in seconds
now = await get_current_timestamp()
time_elapsed = now - data.withdrawtime
withdraw_time_seconds = (
data.withdrawbtwn * 60 if data.withdrawtimeopt != "secs" else data.withdrawbtwn
async def get_clean_tpos(tpos_id: str) -> Optional[TposClean]:
return await db.fetchone(
"SELECT * FROM tpos.pos WHERE id = :id", {"id": tpos_id}, TposClean
)

logger.debug(f"Time between: {time_elapsed} seconds")

# Check if the time between withdrawals is less than withdrawbtwn
assert (
time_elapsed > withdraw_time_seconds
), f"""
Last withdraw was made too recently, please try again in
{int(withdraw_time_seconds - (time_elapsed))} secs"
"""

# Update the withdraw time in the database
await db.execute(
"UPDATE tpos.pos SET withdrawtime = ? WHERE id = ?", (now, tpos_id)
)

tpos = await get_tpos(tpos_id)
assert tpos, "Newly updated tpos couldn't be retrieved"
async def update_tpos(tpos: Tpos) -> Tpos:
await db.update("tpos.pos", tpos)
return tpos


async def update_tpos(tpos_id: str, **kwargs) -> TPoS:
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
await db.execute(
f"UPDATE tpos.pos SET {q} WHERE id = ?", (*kwargs.values(), tpos_id)
)
tpos = await get_tpos(tpos_id)
assert tpos, "Newly updated tpos couldn't be retrieved"
return tpos


async def get_tposs(wallet_ids: Union[str, List[str]]) -> List[TPoS]:
async def get_tposs(wallet_ids: Union[str, list[str]]) -> list[Tpos]:
if isinstance(wallet_ids, str):
wallet_ids = [wallet_ids]

q = ",".join(["?"] * len(wallet_ids))
rows = await db.fetchall(
f"SELECT * FROM tpos.pos WHERE wallet IN ({q})", (*wallet_ids,)
q = ",".join([f"'{wallet_id}'" for wallet_id in wallet_ids])
return await db.fetchall(
f"SELECT * FROM tpos.pos WHERE wallet IN ({q})", model=Tpos
)
return [TPoS(**row) for row in rows]


async def delete_tpos(tpos_id: str) -> None:
await db.execute("DELETE FROM tpos.pos WHERE id = ?", (tpos_id,))
await db.execute("DELETE FROM tpos.pos WHERE id = :id", {"id": tpos_id})
60 changes: 48 additions & 12 deletions migrations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
async def m001_initial(db):
from lnbits.db import Database


async def m001_initial(db: Database):
"""
Initial tposs table.
"""
Expand All @@ -14,7 +17,7 @@ async def m001_initial(db):
)


async def m002_addtip_wallet(db):
async def m002_addtip_wallet(db: Database):
"""
Add tips to tposs table
"""
Expand All @@ -25,7 +28,7 @@ async def m002_addtip_wallet(db):
)


async def m003_addtip_options(db):
async def m003_addtip_options(db: Database):
"""
Add tips to tposs table
"""
Expand All @@ -36,8 +39,7 @@ async def m003_addtip_options(db):
)


async def m004_addwithdrawlimit(db):
rows = [list(row) for row in await db.fetchall("SELECT * FROM tpos.tposs")]
async def m004_addwithdrawlimit(db: Database):
await db.execute(
"""
CREATE TABLE tpos.pos (
Expand All @@ -55,6 +57,8 @@ async def m004_addwithdrawlimit(db):
);
"""
)
result = await db.execute("SELECT * FROM tpos.tposs")
rows = result.mappings().all()
for row in rows:
await db.execute(
"""
Expand All @@ -66,14 +70,21 @@ async def m004_addwithdrawlimit(db):
tip_wallet,
tip_options
)
VALUES (?, ?, ?, ?, ?, ?)
VALUES (:id, :wallet, :name, :currency, :tip_wallet, :tip_options)
""",
(row[0], row[1], row[2], row[3], row[4], row[5]),
{
"id": row["id"],
"wallet": row["wallet"],
"name": row["name"],
"currency": row["currency"],
"tip_wallet": row["tip_wallet"],
"tip_options": row["tip_options"],
},
)
await db.execute("DROP TABLE tpos.tposs")


async def m005_initial(db):
async def m005_initial(db: Database):
"""
Initial withdraws table.
"""
Expand All @@ -89,7 +100,7 @@ async def m005_initial(db):
)


async def m006_items(db):
async def m006_items(db: Database):
"""
Add items to tpos table for storing various items (JSON format)
See `Item` class in models.
Expand All @@ -101,14 +112,14 @@ async def m006_items(db):
)


async def m007_atm_premium(db):
async def m007_atm_premium(db: Database):
"""
Add a premium % to ATM withdraws
"""
await db.execute("ALTER TABLE tpos.pos ADD COLUMN withdrawpremium FLOAT;")


async def m008_atm_time_option_and_pin_toggle(db):
async def m008_atm_time_option_and_pin_toggle(db: Database):
"""
Add a time mins/sec and pin toggle
"""
Expand All @@ -121,11 +132,36 @@ async def m008_atm_time_option_and_pin_toggle(db):
)


async def m009_tax_inclusive(db):
async def m009_tax_inclusive(db: Database):
"""
Add tax_inclusive column
"""
await db.execute(
"ALTER TABLE tpos.pos ADD COLUMN tax_inclusive BOOL NOT NULL DEFAULT true;"
)
await db.execute("ALTER TABLE tpos.pos ADD COLUMN tax_default FLOAT DEFAULT 0;")


async def m010_rename_tpos_withdraw_columns(db: Database):
"""
Add rename tpos withdraw columns
"""
await db.execute(
"""
CREATE TABLE tpos.pos_backup AS
SELECT
id, name, currency, items, wallet, tax_inclusive,
tax_default, tip_wallet, tip_options,
withdrawamt AS withdrawn_amount,
withdrawtime AS withdraw_time,
withdrawbtwn AS withdraw_between,
withdrawlimit AS withdraw_limit,
withdrawtimeopt AS withdraw_time_option,
withdrawpremium AS withdraw_premium,
withdrawpindisabled AS withdraw_pin_disabled,
withdrawpin AS withdraw_pin
FROM tpos.pos
"""
)
await db.execute("DROP TABLE tpos.pos")
await db.execute("ALTER TABLE tpos.pos_backup RENAME TO pos")
Loading