From c87ccf7107041bc84090deabf623d528d00b12cb Mon Sep 17 00:00:00 2001 From: arcbtc Date: Fri, 8 Dec 2023 20:39:27 +0000 Subject: [PATCH] added simple lnurl --- crud.py | 4 +- lnurl.py | 115 +++++++++++++++++++++++- migrations.py | 9 +- models.py | 9 +- templates/{tpos => temp}/_api_docs.html | 0 templates/temp/_temp.html | 18 ++++ templates/{tpos => temp}/index.html | 0 templates/{tpos => temp}/tpos.html | 0 templates/tpos/_tpos.html | 21 ----- views.py | 4 +- views_api.py | 13 ++- 11 files changed, 154 insertions(+), 39 deletions(-) rename templates/{tpos => temp}/_api_docs.html (100%) create mode 100644 templates/temp/_temp.html rename templates/{tpos => temp}/index.html (100%) rename templates/{tpos => temp}/tpos.html (100%) delete mode 100644 templates/tpos/_tpos.html diff --git a/crud.py b/crud.py index e3c8f63..9165075 100644 --- a/crud.py +++ b/crud.py @@ -18,7 +18,9 @@ async def create_temp(wallet_id: str, data: CreateTempData) -> Temp: temp_id, wallet_id, data.name, - data.total + data.total, + data.lnurlpayamount, + data.lnurlwithdrawamount ), ) temp = await get_temp(temp_id) diff --git a/lnurl.py b/lnurl.py index a9a7b82..aecaead 100644 --- a/lnurl.py +++ b/lnurl.py @@ -1 +1,114 @@ -# Maybe your extensions needs some LNURL stuff, for anything LNURL always make sure you are on spec https://github.com/lnurl/luds \ No newline at end of file +# Maybe your extensions needs some LNURL stuff, if so checkout LNURLp/LNURLw extensions/lnurl library in LNbits (to keep things simple the below examples are raw LNURLs) + + +from http import HTTPStatus +from fastapi import Depends, Query, Request +from . import temp_ext +from .crud import get_temp +from lnbits.core.services import create_invoice + + +################################################# +########### A very simple LNURLpay ############## +# https://github.com/lnurl/luds/blob/luds/06.md # +################################################# +################################################# + +@temp_ext.get( + "/api/v1/lnurl/pay/{temp_id}", status_code=HTTPStatus.OK +) +async def api_lnurl_pay( + request: Request, + temp_id: str, +): + temp = await get_temp(temp_id) + if not temp: + return {"status": "ERROR", "reason": "No temp found"} + return { + "callback": str(request.url_for("temp.api_lnurl_pay_callback", temp_id=temp_id)), + "maxSendable": temp.lnurlpayamount, + "minSendable": temp.lnurlpayamount, + "metadata":"[[\"text/plain\", \"" + temp.name + "\"]]", + "tag": "payRequest" + } + +@temp_ext.get( + "/api/v1/lnurl/pay/cb/{temp_id}", + status_code=HTTPStatus.OK, + name="temp.api_lnurl_pay_callback", +) +async def api_lnurl_pay_cb( + request: Request, + temp_id: str, + amount: int = Query(...), +): + temp = await get_temp(temp_id) + if not temp: + return {"status": "ERROR", "reason": "No temp found"} + + payment_request = await create_invoice( + wallet_id=temp.wallet, + amount=int(amount / 1000), + memo=temp.name, + unhashed_description="[[\"text/plain\", \"" + temp.name + "\"]]".encode(), + extra= { + "tag": "temp", + "link": temp_id, + "extra": request.query_params.get("amount"), + }, + ) + return { "pr": payment_request, "routes": []} + +################################################# +######## A very simple LNURLwithdraw ############ +# https://github.com/lnurl/luds/blob/luds/03.md # +################################################# +################################################# + + +@temp_ext.get( + "/api/v1/lnurl/withdraw/{temp_id}", status_code=HTTPStatus.OK +) +async def api_lnurl_pay( + request: Request, + temp_id: str, +): + temp = await get_temp(temp_id) + if not temp: + return {"status": "ERROR", "reason": "No temp found"} + return { + "callback": str(request.url_for("temp.api_lnurl_pay_callback", temp_id=temp_id)), + "maxSendable": temp.lnurlwithdrawamount, + "minSendable": temp.lnurlwithdrawamount, + "k1": "", + "defaultDescription": temp.name, + "metadata":"[[\"text/plain\", \"" + temp.name + "\"]]", + "tag": "withdrawRequest" + } + +@temp_ext.get( + "/api/v1/lnurl/pay/cb/{temp_id}", + status_code=HTTPStatus.OK, + name="temp.api_lnurl_pay_callback", +) +async def api_lnurl_pay_cb( + request: Request, + temp_id: str, + amount: int = Query(...), +): + temp = await get_temp(temp_id) + if not temp: + return {"status": "ERROR", "reason": "No temp found"} + + payment_request = await create_invoice( + wallet_id=temp.wallet, + amount=int(amount / 1000), + memo=temp.name, + unhashed_description="[[\"text/plain\", \"" + temp.name + "\"]]".encode(), + extra= { + "tag": "temp", + "link": temp_id, + "extra": request.query_params.get("amount"), + }, + ) + return { "pr": payment_request, "routes": []} \ No newline at end of file diff --git a/migrations.py b/migrations.py index 7214e62..a3d9c66 100644 --- a/migrations.py +++ b/migrations.py @@ -9,7 +9,10 @@ async def m001_initial(db): CREATE TABLE temp.temp ( id TEXT PRIMARY KEY, wallet TEXT NOT NULL, - name TEXT NOT NULL + name TEXT NOT NULL, + total INTEGER DEFAULT 0, + lnurlpayamount INTEGER DEFAULT 0, + lnurlwithdrawamount INTEGER DEFAULT 0, ); """ ) @@ -23,6 +26,6 @@ async def m002_addtip_wallet(db): """ await db.execute( """ - ALTER TABLE temp.temp ADD total withdrawlimit INTEGER DEFAULT 0,; + ALTER TABLE temp.temp ADD lnurlwithdrawamount withdrawlimit INTEGER DEFAULT 0,; """ - ) + ) \ No newline at end of file diff --git a/models.py b/models.py index 3195103..7b91c52 100644 --- a/models.py +++ b/models.py @@ -2,23 +2,26 @@ from sqlite3 import Row from typing import Optional, List from pydantic import BaseModel +from lnbits.lnurl import encode as lnurl_encode class CreateTempData(BaseModel): wallet: Optional[str] name: Optional[str] total: Optional[int] + lnurlpayamount: Optional[int] + lnurlwithdrawamount: Optional[int] class Temp(BaseModel): id: str wallet: str name: str total: Optional[int] + lnurlpayamount: Optional[int] + lnurlwithdrawamount: Optional[int] @classmethod def from_row(cls, row: Row) -> "Temp": return cls(**dict(row)) class CreateUpdateItemData(BaseModel): - items: List[Item] - -# add something lnurly \ No newline at end of file + items: List[Item] \ No newline at end of file diff --git a/templates/tpos/_api_docs.html b/templates/temp/_api_docs.html similarity index 100% rename from templates/tpos/_api_docs.html rename to templates/temp/_api_docs.html diff --git a/templates/temp/_temp.html b/templates/temp/_temp.html new file mode 100644 index 0000000..82781cd --- /dev/null +++ b/templates/temp/_temp.html @@ -0,0 +1,18 @@ + + + +

+ Temp extension is a basic extension that you can use to get started building your own extension +

+ Created by + Ben Arc. +
+
+
diff --git a/templates/tpos/index.html b/templates/temp/index.html similarity index 100% rename from templates/tpos/index.html rename to templates/temp/index.html diff --git a/templates/tpos/tpos.html b/templates/temp/tpos.html similarity index 100% rename from templates/tpos/tpos.html rename to templates/temp/tpos.html diff --git a/templates/tpos/_tpos.html b/templates/tpos/_tpos.html deleted file mode 100644 index 9157728..0000000 --- a/templates/tpos/_tpos.html +++ /dev/null @@ -1,21 +0,0 @@ - - - -

- Thiago's Point of Sale is a secure, mobile-ready, instant and shareable - point of sale terminal (PoS) for merchants. The PoS is linked to your - LNbits wallet but completely air-gapped so users can ONLY create - invoices. To share the Temp hit the hash on the terminal. -

- Created by - Tiago Vasconcelos. -
-
-
diff --git a/views.py b/views.py index 8cd1fb7..6bdef8e 100644 --- a/views.py +++ b/views.py @@ -49,11 +49,11 @@ async def temp(request: Request, temp_id): ) -# Customise a manifest, or remove manifest completely +# Manifest, customise or remove manifest completely @temp_ext.get("/manifest/{temp_id}.webmanifest") async def manifest(temp_id: str): - remp= await get_temp(temp_id) + temp= await get_temp(temp_id) if not temp: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="Temp does not exist." diff --git a/views_api.py b/views_api.py index 6dc1bc6..3da98d1 100644 --- a/views_api.py +++ b/views_api.py @@ -34,10 +34,7 @@ from .models import CreateTempData, PayLnurlWData, LNURLCharge, CreateUpdateItem ##### ADD YOUR API ENDPOINTS HERE ##### ####################################### - -# TYPICAL ENDPOINTS - -# get all the records belonging to the user +## Get all the records belonging to the user @temp_ext.get("/api/v1/temps", status_code=HTTPStatus.OK) async def api_temps( @@ -50,7 +47,7 @@ async def api_temps( return [temp.dict() for temp in await get_temps(wallet_ids)] -# get a specific record belonging to a user +## Get a specific record belonging to a user @temp_ext.put("/api/v1/temps/{temp_id}") async def api_temp_update( @@ -71,7 +68,7 @@ async def api_temp_update( return temp.dict() -# Create a new record +## Create a new record @temp_ext.post("/api/v1/temps", status_code=HTTPStatus.CREATED) async def api_temp_create( @@ -81,7 +78,7 @@ async def api_temp_create( return temp.dict() -# Delete a record +## Delete a record @temp_ext.delete("/api/v1/temps/{temp_id}") async def api_temp_delete( @@ -103,7 +100,7 @@ async def api_temp_delete( # ANY OTHER ENDPOINTS YOU NEED -# This endpoint creates a payment +## This endpoint creates a payment @tpos_ext.post("/api/v1/temps/payment/{temp_id}", status_code=HTTPStatus.CREATED) async def api_tpos_create_invoice(