Skip to content
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
12 changes: 5 additions & 7 deletions crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ async def create_withdraw_link(
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,
currency=data.currency,
min_withdrawable=int(data.min_withdrawable),
max_withdrawable=int(data.max_withdrawable),
uses=data.uses,
wait_time=data.wait_time,
is_unique=data.is_unique,
Expand Down Expand Up @@ -85,12 +86,10 @@ async def get_withdraw_links(
query_params,
WithdrawLink,
)
result = await db.execute(
f"""
result = await db.execute(f"""
SELECT COUNT(*) as total FROM withdraw.withdraw_link
WHERE wallet IN ({q})
"""
)
""")
result2 = result.mappings().first()

return PaginatedWithdraws(data=links, total=int(result2.total))
Expand Down Expand Up @@ -141,7 +140,6 @@ async def create_hash_check(the_hash: str, lnurl_id: str) -> HashCheck:


async def get_hash_check(the_hash: str, lnurl_id: str) -> HashCheck:

hash_check = await db.fetchone(
"""
SELECT id as hash, lnurl_id as lnurl
Expand Down
13 changes: 13 additions & 0 deletions helpers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from fastapi import Request
from lnbits.utils.exchange_rates import get_fiat_rate_satoshis
from lnurl import Lnurl
from lnurl import encode as lnurl_encode
from shortuuid import uuid
Expand Down Expand Up @@ -26,3 +27,15 @@ def create_lnurl(link: WithdrawLink, req: Request) -> Lnurl:
f"Error creating LNURL with url: `{url!s}`, "
"check your webserver proxy configuration."
) from e


async def min_max_withdrawable(link: WithdrawLink) -> tuple[int, int]:
min_withdrawable = link.min_withdrawable
max_withdrawable = link.max_withdrawable

if link.currency:
rate = await get_fiat_rate_satoshis(link.currency)
min_withdrawable = round(min_withdrawable / 100 * rate)
max_withdrawable = round(max_withdrawable / 100 * rate)

return min_withdrawable, max_withdrawable
22 changes: 10 additions & 12 deletions migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ async def m001_initial(db):
"""
Creates an improved withdraw table and migrates the existing data.
"""
await db.execute(
f"""
await db.execute(f"""
CREATE TABLE withdraw.withdraw_links (
id TEXT PRIMARY KEY,
wallet TEXT,
Expand All @@ -19,16 +18,14 @@ async def m001_initial(db):
used INTEGER DEFAULT 0,
usescsv TEXT
);
"""
)
""")


async def m002_change_withdraw_table(db):
"""
Creates an improved withdraw table and migrates the existing data.
"""
await db.execute(
f"""
await db.execute(f"""
CREATE TABLE withdraw.withdraw_link (
id TEXT PRIMARY KEY,
wallet TEXT,
Expand All @@ -44,8 +41,7 @@ async def m002_change_withdraw_table(db):
used INTEGER DEFAULT 0,
usescsv TEXT
);
"""
)
""")

for row in [
list(row) for row in await db.fetchall("SELECT * FROM withdraw.withdraw_links")
Expand Down Expand Up @@ -100,14 +96,12 @@ async def m003_make_hash_check(db):
"""
Creates a hash check table.
"""
await db.execute(
"""
await db.execute("""
CREATE TABLE withdraw.hash_check (
id TEXT PRIMARY KEY,
lnurl_id TEXT
);
"""
)
""")


async def m004_webhook_url(db):
Expand Down Expand Up @@ -145,3 +139,7 @@ async def m008_add_enabled_column(db):
await db.execute(
"ALTER TABLE withdraw.withdraw_link ADD COLUMN enabled BOOLEAN DEFAULT true;"
)


async def m009_add_currency(db):
await db.execute("ALTER TABLE withdraw.withdraw_link ADD COLUMN currency TEXT;")
6 changes: 4 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

class CreateWithdrawData(BaseModel):
title: str = Query(...)
min_withdrawable: int = Query(..., ge=1)
max_withdrawable: int = Query(..., ge=1)
min_withdrawable: float = Query(..., ge=0.01)
max_withdrawable: float = Query(..., ge=0.01)
Comment thread
dni marked this conversation as resolved.
uses: int = Query(..., ge=1)
wait_time: int = Query(..., ge=1)
is_unique: bool
Expand All @@ -16,6 +16,7 @@ class CreateWithdrawData(BaseModel):
webhook_body: str = Query(None)
custom_url: str = Query(None)
enabled: bool = Query(True)
currency: str = Query(None)


class WithdrawLink(BaseModel):
Expand All @@ -39,6 +40,7 @@ class WithdrawLink(BaseModel):
custom_url: str = Query(None)
created_at: datetime
enabled: bool = Query(True)
currency: str = Query(None)
lnurl: str | None = Field(
default=None,
no_database=True,
Expand Down
51 changes: 49 additions & 2 deletions static/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ const mapWithdrawLink = function (obj) {
obj._data = _.clone(obj)
obj.uses_left = obj.uses - obj.used
obj._data.use_custom = Boolean(obj.custom_url)
if (obj.currency) {
obj.min_withdrawable = obj.min_withdrawable / 100
obj.max_withdrawable = obj.max_withdrawable / 100
}
return obj
}

Expand All @@ -14,6 +18,7 @@ window.app = Vue.createApp({
return {
checker: null,
withdrawLinks: [],
currencyOptions: [],
lnurl: '',
withdrawLinksTable: {
columns: [
Expand Down Expand Up @@ -46,12 +51,24 @@ window.app = Vue.createApp({
label: 'Uses left',
field: 'uses_left'
},
{
name: 'currency',
align: 'right',
label: 'Currency',
field: 'currency',
format: function (val) {
return val ? val.toUpperCase() : 'sat'
}
},
{
name: 'max_withdrawable',
align: 'right',
label: 'Max (sat)',
label: `Max`,
field: 'max_withdrawable',
format: LNbits.utils.formatSat
format: (val, row) =>
row.currency
? LNbits.utils.formatCurrency(val, row.currency)
: val
}
],
pagination: {
Expand Down Expand Up @@ -94,6 +111,24 @@ window.app = Vue.createApp({
return this.withdrawLinks.sort(function (a, b) {
return b.uses_left - a.uses_left
})
},
assertMinimumWithdrawable() {
const dialog = this.formDialog.show
? this.formDialog
: this.simpleformDialog
return dialog.data.currency
? dialog.data.min_withdrawable >= 0.01
: dialog.data.min_withdrawable >= 1
},
assertMaximumWithdrawable() {
const dialog = this.formDialog.show
? this.formDialog
: this.simpleformDialog
return dialog.data.currency
? dialog.data.max_withdrawable >= 0.01 &&
dialog.data.max_withdrawable >= dialog.data.min_withdrawable
: dialog.data.max_withdrawable >= 1 &&
dialog.data.max_withdrawable >= dialog.data.min_withdrawable
}
},
methods: {
Expand Down Expand Up @@ -164,6 +199,11 @@ window.app = Vue.createApp({
data.custom_url = CUSTOM_URL
}

if (data.currency) {
data.min_withdrawable = data.min_withdrawable * 100
data.max_withdrawable = data.max_withdrawable * 100
}

data.wait_time =
data.wait_time *
{
Expand Down Expand Up @@ -197,6 +237,11 @@ window.app = Vue.createApp({
data.custom_url = '/static/images/default_voucher.png'
}

if (data.currency) {
data.min_withdrawable = data.min_withdrawable * 100
data.max_withdrawable = data.max_withdrawable * 100
}

if (data.id) {
this.updateWithdrawLink(wallet, data)
} else {
Expand Down Expand Up @@ -231,6 +276,7 @@ window.app = Vue.createApp({
})
},
createWithdrawLink(wallet, data) {
console.log(data)
LNbits.api
.request('POST', '/withdraw/api/v1/links', wallet.adminkey, data)
.then(response => {
Expand Down Expand Up @@ -314,5 +360,6 @@ window.app = Vue.createApp({
this.getWithdrawLinks()
this.checker = setInterval(this.getWithdrawLinks, 300000)
}
this.currencyOptions = this.g.allowedCurrencies
}
})
48 changes: 33 additions & 15 deletions templates/withdraw/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,21 +172,33 @@ <h6 class="text-subtitle1 q-my-none">
type="text"
label="Link title *"
></q-input>
<q-select
filled
dense
clearable
v-model="formDialog.data.currency"
:options="currencyOptions"
label="Currency (optional)"
hint="Leave blank for sats"
>
</q-select>
<q-input
filled
dense
v-model.number="formDialog.data.min_withdrawable"
type="number"
min="10"
label="Min withdrawable (sat, at least 10) *"
:min="formDialog.data.currency ? 0.01 : 10"
:step="formDialog.data.currency ? 0.01 : 1"
:label="formDialog.data.currency ? 'Min withdrawable (' + formDialog.data.currency + ', at least 0.01) *' : 'Min withdrawable (sat, at least 10) *'"
></q-input>
<q-input
filled
dense
v-model.number="formDialog.data.max_withdrawable"
type="number"
min="10"
label="Max withdrawable (sat, at least 10) *"
:min="formDialog.data.currency ? 0.01 : 10"
:step="formDialog.data.currency ? 0.01 : 1"
:label="formDialog.data.currency ? 'Max withdrawable (' + formDialog.data.currency + ', at least 0.01) *' : 'Max withdrawable (sat, at least 10) *'"
></q-input>
<q-input
filled
Expand Down Expand Up @@ -325,12 +337,8 @@ <h6 class="text-subtitle1 q-my-none">
:disable="
formDialog.data.wallet == null ||
formDialog.data.title == null ||
(formDialog.data.min_withdrawable == null || formDialog.data.min_withdrawable < 1) ||
(
formDialog.data.max_withdrawable == null ||
formDialog.data.max_withdrawable < 1 ||
formDialog.data.max_withdrawable < formDialog.data.min_withdrawable
) ||
!assertMinimumWithdrawable ||
!assertMaximumWithdrawable ||
formDialog.data.uses == null ||
formDialog.data.wait_time == null"
type="submit"
Expand Down Expand Up @@ -360,13 +368,24 @@ <h6 class="text-subtitle1 q-my-none">
label="Wallet *"
>
</q-select>
<q-select
filled
dense
clearable
v-model="simpleformDialog.data.currency"
:options="currencyOptions"
label="Currency (optional)"
hint="Leave blank for sats"
>
</q-select>
<q-input
filled
dense
v-model.number="simpleformDialog.data.max_withdrawable"
type="number"
min="10"
label="Withdraw amount per voucher (sat, at least 10)"
:min="simpleformDialog.data.currency ? 0.01 : 10"
:step="simpleformDialog.data.currency ? 0.01 : 1"
:label="simpleformDialog.data.currency ? 'Withdraw amount per voucher (' + simpleformDialog.data.currency + ', at least 0.01)' : 'Withdraw amount per voucher (sat, at least 10)'"
></q-input>
<q-input
filled
Expand Down Expand Up @@ -424,9 +443,8 @@ <h6 class="text-subtitle1 q-my-none">
color="primary"
:disable="
simpleformDialog.data.wallet == null ||

simpleformDialog.data.max_withdrawable == null ||
simpleformDialog.data.max_withdrawable < 1 ||
simpleformDialog.data.max_withdrawable == null ||
!assertMaximumWithdrawable ||
simpleformDialog.data.uses == null"
type="submit"
>Create vouchers</q-btn
Expand Down
Loading
Loading