Skip to content

Commit f981e7e

Browse files
authored
Merge pull request #64 from lnbits/atm_withdraw_boltcard
allow withdraw with boltcard
2 parents 1314d54 + 7dcffb3 commit f981e7e

File tree

2 files changed

+106
-5
lines changed

2 files changed

+106
-5
lines changed

templates/tpos/tpos.html

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,9 @@ <h5 class="q-mt-none q-mb-sm">
829829
// if searchTerm entered, filter out items that don't match
830830
if (this.searchTerm) {
831831
items = items.filter(item => {
832-
return item.title.toLowerCase().includes(this.searchTerm.toLowerCase())
832+
return item.title
833+
.toLowerCase()
834+
.includes(this.searchTerm.toLowerCase())
833835
})
834836
}
835837
// if categoryFilter entered, filter out items that don't match
@@ -920,6 +922,7 @@ <h5 class="q-mt-none q-mb-sm">
920922
lnurl = res.data.lnurl
921923
dialog.data = {payment_request: lnurl}
922924
dialog.show = true
925+
self.readNfcTag()
923926
dialog.dismissMsg = self.$q.notify({
924927
timeout: 0,
925928
message: 'Withdraw...'
@@ -949,6 +952,7 @@ <h5 class="q-mt-none q-mb-sm">
949952
self.atmToken = ''
950953
self.complete.show = true
951954
self.atmMode = false
955+
this.connectionWithdraw.close()
952956
}
953957
}
954958
this.getRates()
@@ -1108,7 +1112,9 @@ <h5 class="q-mt-none q-mb-sm">
11081112

11091113
this.nfcTagReading = true
11101114
this.$q.notify({
1111-
message: 'Tap your NFC tag to pay this invoice with LNURLw.'
1115+
message: this.atmMode
1116+
? 'Tap your NFC tag to withdraw with LNURLp.'
1117+
: 'Tap your NFC tag to pay this invoice with LNURLw.'
11121118
})
11131119

11141120
return ndef.scan({signal: readerAbortController.signal}).then(() => {
@@ -1136,7 +1142,15 @@ <h5 class="q-mt-none q-mb-sm">
11361142

11371143
//User feedback, show loader icon
11381144
self.nfcTagReading = false
1139-
self.payInvoice(lnurl, readerAbortController)
1145+
if (self.atmMode) {
1146+
LNbits.api
1147+
.request('GET', `${lnurl.replace('lnurlw://', 'https://')}`)
1148+
.then(res => {
1149+
self.makeWithdraw(res.data.payLink)
1150+
})
1151+
} else {
1152+
self.payInvoice(lnurl, readerAbortController)
1153+
}
11401154

11411155
this.$q.notify({
11421156
type: 'positive',
@@ -1154,6 +1168,36 @@ <h5 class="q-mt-none q-mb-sm">
11541168
})
11551169
}
11561170
},
1171+
makeWithdraw(payLink, readerAbortController) {
1172+
if (!payLink) {
1173+
this.$q.notify({
1174+
type: 'negative',
1175+
message: 'LNURL not found in NFC tag.'
1176+
})
1177+
return
1178+
}
1179+
LNbits.api
1180+
.request(
1181+
'GET',
1182+
`/tpos/api/v1/atm/withdraw/${this.atmToken}/${this.sat}/pay?payLink=${payLink}`
1183+
)
1184+
.then(res => {
1185+
if (!res.data.success) {
1186+
this.$q.notify({
1187+
type: 'negative',
1188+
message: res.data.detail
1189+
})
1190+
} else {
1191+
this.stack = []
1192+
this.total = 0.0
1193+
this.$q.notify({
1194+
type: 'positive',
1195+
message: 'Topup successful!'
1196+
})
1197+
}
1198+
readerAbortController.abort()
1199+
})
1200+
},
11571201
payInvoice: function (lnurl, readerAbortController) {
11581202
const self = this
11591203

views_api.py

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@
1313
from lnbits.core.views.api import api_payment
1414
from lnbits.decorators import (
1515
WalletTypeInfo,
16-
check_admin,
1716
get_key_type,
1817
require_admin_key,
19-
require_invoice_key,
2018
)
2119
from lnbits.utils.exchange_rates import get_fiat_rate_satoshis
2220

@@ -245,6 +243,65 @@ async def api_tpos_atm_pin_check(tpos_id: str, atmpin: int):
245243
return token
246244

247245

246+
@tpos_ext.get("/api/v1/atm/withdraw/{k1}/{amount}/pay", status_code=HTTPStatus.OK)
247+
async def api_tpos_atm_pay(
248+
request: Request, k1: str, amount: int, payLink: str = Query(...)
249+
):
250+
try:
251+
# get the payment_request from the lnurl
252+
payLink = payLink.replace("lnurlp://", "https://")
253+
logger.debug(payLink)
254+
async with httpx.AsyncClient() as client:
255+
headers = {"user-agent": f"lnbits/tpos"}
256+
r = await client.get(payLink, follow_redirects=True, headers=headers)
257+
if r.is_error:
258+
return {"success": False, "detail": "Error loading"}
259+
resp = r.json()
260+
261+
amount = amount * 1000 # convert to msats
262+
263+
if resp["tag"] != "payRequest":
264+
return {"success": False, "detail": "Wrong tag type"}
265+
266+
if amount < resp["minSendable"]:
267+
return {"success": False, "detail": "Amount too low"}
268+
269+
if amount > resp["maxSendable"]:
270+
return {"success": False, "detail": "Amount too high"}
271+
272+
cb_res = await client.get(
273+
resp["callback"],
274+
follow_redirects=True,
275+
headers=headers,
276+
params={"amount": amount},
277+
)
278+
cb_resp = cb_res.json()
279+
if cb_res.is_error:
280+
return {"success": False, "detail": "Error loading callback"}
281+
282+
# pay the invoice
283+
lnurl_cb_url = str(request.url_for("tpos.tposlnurlcharge.callback"))
284+
pay_invoice = await client.get(
285+
lnurl_cb_url,
286+
params={"pr": cb_resp["pr"], "k1": k1},
287+
)
288+
if pay_invoice.status_code != 200:
289+
return {"success": False, "detail": "Error paying invoice"}
290+
return {"success": True, "detail": "Payment successful"}
291+
292+
except AssertionError as ex:
293+
raise HTTPException(
294+
status_code=HTTPStatus.BAD_REQUEST,
295+
detail=str(ex),
296+
)
297+
except Exception as ex:
298+
logger.warning(ex)
299+
raise HTTPException(
300+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
301+
detail="Cannot process atm withdraw",
302+
)
303+
304+
248305
@tpos_ext.get(
249306
"/api/v1/atm/withdraw/{withdraw_token}/{amount}", status_code=HTTPStatus.CREATED
250307
)

0 commit comments

Comments
 (0)