diff --git a/__init__.py b/__init__.py index f60ed98..0b72c14 100644 --- a/__init__.py +++ b/__init__.py @@ -8,9 +8,7 @@ from lnbits.tasks import catch_everything_and_restart db = Database("ext_myextension") -myextension_ext: APIRouter = APIRouter( - prefix="/myextension", tags=["MyExtension"] -) +myextension_ext: APIRouter = APIRouter(prefix="/myextension", tags=["MyExtension"]) temp_static_files = [ { @@ -19,14 +17,17 @@ temp_static_files = [ } ] + def myextension_renderer(): return template_renderer(["myextension/templates"]) + from .lnurl import * from .tasks import wait_for_paid_invoices from .views import * from .views_api import * + def myextension_start(): loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) \ No newline at end of file + loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/crud.py b/crud.py index ddc85c6..78b09a0 100644 --- a/crud.py +++ b/crud.py @@ -9,7 +9,10 @@ from fastapi import Request from lnurl import encode as lnurl_encode import shortuuid -async def create_myextension(wallet_id: str, data: CreateMyExtensionData, req: Request) -> MyExtension: + +async def create_myextension( + wallet_id: str, data: CreateMyExtensionData, req: Request +) -> MyExtension: myextension_id = urlsafe_short_hash() await db.execute( """ @@ -21,7 +24,7 @@ async def create_myextension(wallet_id: str, data: CreateMyExtensionData, req: R wallet_id, data.name, data.lnurlpayamount, - data.lnurlwithdrawamount + data.lnurlwithdrawamount, ), ) myextension = await get_myextension(myextension_id, req) @@ -29,25 +32,33 @@ async def create_myextension(wallet_id: str, data: CreateMyExtensionData, req: R return myextension -async def get_myextension(myextension_id: str, req: Optional[Request] = None) -> Optional[MyExtension]: +async def get_myextension( + myextension_id: str, req: Optional[Request] = None +) -> Optional[MyExtension]: logger.debug(myextension_id) - row = await db.fetchone("SELECT * FROM myextension.maintable WHERE id = ?", (myextension_id,)) + row = await db.fetchone( + "SELECT * FROM myextension.maintable WHERE id = ?", (myextension_id,) + ) if not row: return None rowAmended = MyExtension(**row) if req: rowAmended.lnurlpay = lnurl_encode( - req.url_for("myextension.api_lnurl_pay", - myextension_id=row.id)._url - ) + req.url_for("myextension.api_lnurl_pay", myextension_id=row.id)._url + ) rowAmended.lnurlwithdraw = lnurl_encode( - req.url_for("myextension.api_lnurl_withdraw", - myextension_id=row.id, - tickerhash=shortuuid.uuid(name=rowAmended.id + str(rowAmended.ticker)))._url - ) + req.url_for( + "myextension.api_lnurl_withdraw", + myextension_id=row.id, + tickerhash=shortuuid.uuid(name=rowAmended.id + str(rowAmended.ticker)), + )._url + ) return rowAmended -async def get_myextensions(wallet_ids: Union[str, List[str]], req: Optional[Request] = None) -> List[MyExtension]: + +async def get_myextensions( + wallet_ids: Union[str, List[str]], req: Optional[Request] = None +) -> List[MyExtension]: if isinstance(wallet_ids, str): wallet_ids = [wallet_ids] @@ -59,25 +70,33 @@ async def get_myextensions(wallet_ids: Union[str, List[str]], req: Optional[Requ if req: for row in tempRows: row.lnurlpay = lnurl_encode( - req.url_for("myextension.api_lnurl_pay", - myextension_id=row.id)._url - ) + req.url_for("myextension.api_lnurl_pay", myextension_id=row.id)._url + ) row.lnurlwithdraw = lnurl_encode( - req.url_for("myextension.api_lnurl_withdraw", - myextension_id=row.id, - tickerhash=shortuuid.uuid(name=row.id + str(row.ticker)))._url + req.url_for( + "myextension.api_lnurl_withdraw", + myextension_id=row.id, + tickerhash=shortuuid.uuid(name=row.id + str(row.ticker)), + )._url ) return tempRows -async def update_myextension(myextension_id: str, req: Optional[Request] = None, **kwargs) -> MyExtension: + +async def update_myextension( + myextension_id: str, req: Optional[Request] = None, **kwargs +) -> MyExtension: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - logger.debug( kwargs.items()) + logger.debug(kwargs.items()) await db.execute( - f"UPDATE myextension.maintable SET {q} WHERE id = ?", (*kwargs.values(), myextension_id) + f"UPDATE myextension.maintable SET {q} WHERE id = ?", + (*kwargs.values(), myextension_id), ) myextension = await get_myextension(myextension_id, req) assert myextension, "Newly updated myextension couldn't be retrieved" return myextension + async def delete_myextension(myextension_id: str) -> None: - await db.execute("DELETE FROM myextension.maintable WHERE id = ?", (myextension_id,)) \ No newline at end of file + await db.execute( + "DELETE FROM myextension.maintable WHERE id = ?", (myextension_id,) + ) diff --git a/lnurl.py b/lnurl.py index 6e6ddeb..6cdd0bd 100644 --- a/lnurl.py +++ b/lnurl.py @@ -19,8 +19,9 @@ import shortuuid ################################################# ################################################# + @myextension_ext.get( - "/api/v1/lnurl/pay/{myextension_id}", + "/api/v1/lnurl/pay/{myextension_id}", status_code=HTTPStatus.OK, name="myextension.api_lnurl_pay", ) @@ -32,15 +33,20 @@ async def api_lnurl_pay( if not myextension: return {"status": "ERROR", "reason": "No myextension found"} return { - "callback": str(request.url_for("myextension.api_lnurl_pay_callback", myextension_id=myextension_id)), - "maxSendable": myextension.lnurlpayamount * 1000, - "minSendable": myextension.lnurlpayamount * 1000, - "metadata":"[[\"text/plain\", \"" + myextension.name + "\"]]", - "tag": "payRequest" - } + "callback": str( + request.url_for( + "myextension.api_lnurl_pay_callback", myextension_id=myextension_id + ) + ), + "maxSendable": myextension.lnurlpayamount * 1000, + "minSendable": myextension.lnurlpayamount * 1000, + "metadata": '[["text/plain", "' + myextension.name + '"]]', + "tag": "payRequest", + } + @myextension_ext.get( - "/api/v1/lnurl/pay/cb/{myextension_id}", + "/api/v1/lnurl/pay/cb/{myextension_id}", status_code=HTTPStatus.OK, name="myextension.api_lnurl_pay_callback", ) @@ -53,27 +59,25 @@ async def api_lnurl_pay_cb( logger.debug(myextension) if not myextension: return {"status": "ERROR", "reason": "No myextension found"} - + payment_hash, payment_request = await create_invoice( wallet_id=myextension.wallet, amount=int(amount / 1000), memo=myextension.name, - unhashed_description=f"[[\"text/plain\", \"{myextension.name}\"]]".encode(), - extra= { + unhashed_description=f'[["text/plain", "{myextension.name}"]]'.encode(), + extra={ "tag": "MyExtension", "myextensionId": myextension_id, "extra": request.query_params.get("amount"), }, ) return { - "pr": payment_request, + "pr": payment_request, "routes": [], - "successAction": { - "tag": "message", - "message": f"Paid {myextension.name}" - } + "successAction": {"tag": "message", "message": f"Paid {myextension.name}"}, } + ################################################# ######## A very simple LNURLwithdraw ############ # https://github.com/lnurl/luds/blob/luds/03.md # @@ -99,16 +103,21 @@ async def api_lnurl_withdraw( return {"status": "ERROR", "reason": "LNURLw already used"} return { - "tag": "withdrawRequest", - "callback": str(request.url_for("myextension.api_lnurl_withdraw_callback", myextension_id=myextension_id)), - "k1": k1, - "defaultDescription": myextension.name, - "maxWithdrawable": myextension.lnurlwithdrawamount * 1000, - "minWithdrawable": myextension.lnurlwithdrawamount * 1000 - } + "tag": "withdrawRequest", + "callback": str( + request.url_for( + "myextension.api_lnurl_withdraw_callback", myextension_id=myextension_id + ) + ), + "k1": k1, + "defaultDescription": myextension.name, + "maxWithdrawable": myextension.lnurlwithdrawamount * 1000, + "minWithdrawable": myextension.lnurlwithdrawamount * 1000, + } + @myextension_ext.get( - "/api/v1/lnurl/withdraw/cb/{myextension_id}", + "/api/v1/lnurl/withdraw/cb/{myextension_id}", status_code=HTTPStatus.OK, name="myextension.api_lnurl_withdraw_callback", ) @@ -125,12 +134,14 @@ async def api_lnurl_withdraw_cb( myextension = await get_myextension(myextension_id) if not myextension: return {"status": "ERROR", "reason": "No myextension found"} - + k1Check = shortuuid.uuid(name=myextension.id + str(myextension.ticker)) if k1Check != k1: return {"status": "ERROR", "reason": "Wrong k1 check provided"} - await update_myextension(myextension_id=myextension_id, ticker=myextension.ticker + 1) + await update_myextension( + myextension_id=myextension_id, ticker=myextension.ticker + 1 + ) logger.debug(myextension.wallet) logger.debug(pr) logger.debug(int(myextension.lnurlwithdrawamount * 1000)) @@ -138,6 +149,10 @@ async def api_lnurl_withdraw_cb( wallet_id=myextension.wallet, payment_request=pr, max_sat=int(myextension.lnurlwithdrawamount * 1000), - extra={"tag": "MyExtension", "myextensionId": myextension_id, "lnurlwithdraw": True} + extra={ + "tag": "MyExtension", + "myextensionId": myextension_id, + "lnurlwithdraw": True, + }, ) - return {"status": "OK"} \ No newline at end of file + return {"status": "OK"} diff --git a/migrations.py b/migrations.py index 40725e3..b3d4f76 100644 --- a/migrations.py +++ b/migrations.py @@ -1,5 +1,6 @@ # The migration file is like a blockchain, never edit only add! + async def m001_initial(db): """ Initial templates table. @@ -19,8 +20,10 @@ async def m001_initial(db): """ ) + # Here we add another field to the database + async def m002_addtip_wallet(db): """ Add total to templates table @@ -29,4 +32,4 @@ async def m002_addtip_wallet(db): """ ALTER TABLE myextension.maintable ADD ticker INTEGER DEFAULT 1; """ - ) \ No newline at end of file + ) diff --git a/models.py b/models.py index 39cec07..1f91cfe 100644 --- a/models.py +++ b/models.py @@ -9,6 +9,7 @@ from fastapi import Request from lnbits.lnurl import encode as lnurl_encode from urllib.parse import urlparse + class CreateMyExtensionData(BaseModel): wallet: Optional[str] name: Optional[str] @@ -17,6 +18,7 @@ class CreateMyExtensionData(BaseModel): lnurlwithdrawamount: Optional[int] ticker: Optional[int] + class MyExtension(BaseModel): id: str wallet: Optional[str] @@ -30,4 +32,4 @@ class MyExtension(BaseModel): @classmethod def from_row(cls, row: Row) -> "MyExtension": - return cls(**dict(row)) \ No newline at end of file + return cls(**dict(row)) diff --git a/tasks.py b/tasks.py index 1f46c8a..545faf6 100644 --- a/tasks.py +++ b/tasks.py @@ -29,6 +29,7 @@ async def wait_for_paid_invoices(): # do somethhing when an invoice related top this extension is paid + async def on_invoice_paid(payment: Payment) -> None: logger.debug("payment received for myextension extension") if payment.extra.get("tag") != "MyExtension": @@ -42,20 +43,18 @@ async def on_invoice_paid(payment: Payment) -> None: total = myextension.total - payment.amount else: total = myextension.total + payment.amount - data_to_update = { - "total": total - } - + data_to_update = {"total": total} + await update_myextension(myextension_id=myextension_id, **data_to_update) # here we could send some data to a websocket on wss:///api/v1/ws/ # and then listen to it on the frontend, which we do with index.html connectWebocket() - + some_payment_data = { "name": myextension.name, "amount": payment.amount, "fee": payment.fee, - "checking_id": payment.checking_id + "checking_id": payment.checking_id, } await websocketUpdater(myextension_id, str(some_payment_data)) diff --git a/templates/myextension/_api_docs.html b/templates/myextension/_api_docs.html index 70d1fd4..5316309 100644 --- a/templates/myextension/_api_docs.html +++ b/templates/myextension/_api_docs.html @@ -1,8 +1,3 @@ - + - + \ No newline at end of file diff --git a/templates/myextension/_myextension.html b/templates/myextension/_myextension.html index 09e4c31..16ff645 100644 --- a/templates/myextension/_myextension.html +++ b/templates/myextension/_myextension.html @@ -4,24 +4,10 @@

Some more info about my excellent extension.

- Created by - Ben Arc. - Repo - MyExtension. + Created by + Ben Arc. + Repo + MyExtension. - + \ No newline at end of file diff --git a/templates/myextension/index.html b/templates/myextension/index.html index 4e8c494..278e40c 100644 --- a/templates/myextension/index.html +++ b/templates/myextension/index.html @@ -4,10 +4,8 @@
- New MyExtension - + New MyExtension + @@ -20,14 +18,8 @@ Export to CSV
- + @@ -38,63 +30,30 @@ @@ -107,7 +66,8 @@
{{SITE_TITLE}} MyExtension extension
-

Simple extension you can use as a base for your own extension.
Includes very simple LNURL-pay and LNURL-withdraw example.

+

Simple extension you can use as a base for your own extension.
Includes very simple LNURL-pay and + LNURL-withdraw example.

@@ -123,54 +83,20 @@ - - - - + + + +
- Update MyExtension - Update MyExtension + Create MyExtension - Cancel + type="submit">Create MyExtension + Cancel
@@ -178,31 +104,30 @@ - + - - -
-
+ + +
+
- +
lnurlpay - +
lnurlwithdraw - +