format
This commit is contained in:
parent
66d44f95fb
commit
2cac36be17
12 changed files with 272 additions and 311 deletions
|
|
@ -8,9 +8,7 @@ from lnbits.tasks import catch_everything_and_restart
|
||||||
|
|
||||||
db = Database("ext_myextension")
|
db = Database("ext_myextension")
|
||||||
|
|
||||||
myextension_ext: APIRouter = APIRouter(
|
myextension_ext: APIRouter = APIRouter(prefix="/myextension", tags=["MyExtension"])
|
||||||
prefix="/myextension", tags=["MyExtension"]
|
|
||||||
)
|
|
||||||
|
|
||||||
temp_static_files = [
|
temp_static_files = [
|
||||||
{
|
{
|
||||||
|
|
@ -19,14 +17,17 @@ temp_static_files = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def myextension_renderer():
|
def myextension_renderer():
|
||||||
return template_renderer(["myextension/templates"])
|
return template_renderer(["myextension/templates"])
|
||||||
|
|
||||||
|
|
||||||
from .lnurl import *
|
from .lnurl import *
|
||||||
from .tasks import wait_for_paid_invoices
|
from .tasks import wait_for_paid_invoices
|
||||||
from .views import *
|
from .views import *
|
||||||
from .views_api import *
|
from .views_api import *
|
||||||
|
|
||||||
|
|
||||||
def myextension_start():
|
def myextension_start():
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
|
loop.create_task(catch_everything_and_restart(wait_for_paid_invoices))
|
||||||
|
|
|
||||||
63
crud.py
63
crud.py
|
|
@ -9,7 +9,10 @@ from fastapi import Request
|
||||||
from lnurl import encode as lnurl_encode
|
from lnurl import encode as lnurl_encode
|
||||||
import shortuuid
|
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()
|
myextension_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
@ -21,7 +24,7 @@ async def create_myextension(wallet_id: str, data: CreateMyExtensionData, req: R
|
||||||
wallet_id,
|
wallet_id,
|
||||||
data.name,
|
data.name,
|
||||||
data.lnurlpayamount,
|
data.lnurlpayamount,
|
||||||
data.lnurlwithdrawamount
|
data.lnurlwithdrawamount,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
myextension = await get_myextension(myextension_id, req)
|
myextension = await get_myextension(myextension_id, req)
|
||||||
|
|
@ -29,25 +32,33 @@ async def create_myextension(wallet_id: str, data: CreateMyExtensionData, req: R
|
||||||
return myextension
|
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)
|
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:
|
if not row:
|
||||||
return None
|
return None
|
||||||
rowAmended = MyExtension(**row)
|
rowAmended = MyExtension(**row)
|
||||||
if req:
|
if req:
|
||||||
rowAmended.lnurlpay = lnurl_encode(
|
rowAmended.lnurlpay = lnurl_encode(
|
||||||
req.url_for("myextension.api_lnurl_pay",
|
req.url_for("myextension.api_lnurl_pay", myextension_id=row.id)._url
|
||||||
myextension_id=row.id)._url
|
)
|
||||||
)
|
|
||||||
rowAmended.lnurlwithdraw = lnurl_encode(
|
rowAmended.lnurlwithdraw = lnurl_encode(
|
||||||
req.url_for("myextension.api_lnurl_withdraw",
|
req.url_for(
|
||||||
myextension_id=row.id,
|
"myextension.api_lnurl_withdraw",
|
||||||
tickerhash=shortuuid.uuid(name=rowAmended.id + str(rowAmended.ticker)))._url
|
myextension_id=row.id,
|
||||||
)
|
tickerhash=shortuuid.uuid(name=rowAmended.id + str(rowAmended.ticker)),
|
||||||
|
)._url
|
||||||
|
)
|
||||||
return rowAmended
|
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):
|
if isinstance(wallet_ids, str):
|
||||||
wallet_ids = [wallet_ids]
|
wallet_ids = [wallet_ids]
|
||||||
|
|
||||||
|
|
@ -59,25 +70,33 @@ async def get_myextensions(wallet_ids: Union[str, List[str]], req: Optional[Requ
|
||||||
if req:
|
if req:
|
||||||
for row in tempRows:
|
for row in tempRows:
|
||||||
row.lnurlpay = lnurl_encode(
|
row.lnurlpay = lnurl_encode(
|
||||||
req.url_for("myextension.api_lnurl_pay",
|
req.url_for("myextension.api_lnurl_pay", myextension_id=row.id)._url
|
||||||
myextension_id=row.id)._url
|
)
|
||||||
)
|
|
||||||
row.lnurlwithdraw = lnurl_encode(
|
row.lnurlwithdraw = lnurl_encode(
|
||||||
req.url_for("myextension.api_lnurl_withdraw",
|
req.url_for(
|
||||||
myextension_id=row.id,
|
"myextension.api_lnurl_withdraw",
|
||||||
tickerhash=shortuuid.uuid(name=row.id + str(row.ticker)))._url
|
myextension_id=row.id,
|
||||||
|
tickerhash=shortuuid.uuid(name=row.id + str(row.ticker)),
|
||||||
|
)._url
|
||||||
)
|
)
|
||||||
return tempRows
|
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()])
|
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||||
logger.debug( kwargs.items())
|
logger.debug(kwargs.items())
|
||||||
await db.execute(
|
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)
|
myextension = await get_myextension(myextension_id, req)
|
||||||
assert myextension, "Newly updated myextension couldn't be retrieved"
|
assert myextension, "Newly updated myextension couldn't be retrieved"
|
||||||
return myextension
|
return myextension
|
||||||
|
|
||||||
|
|
||||||
async def delete_myextension(myextension_id: str) -> None:
|
async def delete_myextension(myextension_id: str) -> None:
|
||||||
await db.execute("DELETE FROM myextension.maintable WHERE id = ?", (myextension_id,))
|
await db.execute(
|
||||||
|
"DELETE FROM myextension.maintable WHERE id = ?", (myextension_id,)
|
||||||
|
)
|
||||||
|
|
|
||||||
71
lnurl.py
71
lnurl.py
|
|
@ -19,8 +19,9 @@ import shortuuid
|
||||||
#################################################
|
#################################################
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get(
|
@myextension_ext.get(
|
||||||
"/api/v1/lnurl/pay/{myextension_id}",
|
"/api/v1/lnurl/pay/{myextension_id}",
|
||||||
status_code=HTTPStatus.OK,
|
status_code=HTTPStatus.OK,
|
||||||
name="myextension.api_lnurl_pay",
|
name="myextension.api_lnurl_pay",
|
||||||
)
|
)
|
||||||
|
|
@ -32,15 +33,20 @@ async def api_lnurl_pay(
|
||||||
if not myextension:
|
if not myextension:
|
||||||
return {"status": "ERROR", "reason": "No myextension found"}
|
return {"status": "ERROR", "reason": "No myextension found"}
|
||||||
return {
|
return {
|
||||||
"callback": str(request.url_for("myextension.api_lnurl_pay_callback", myextension_id=myextension_id)),
|
"callback": str(
|
||||||
"maxSendable": myextension.lnurlpayamount * 1000,
|
request.url_for(
|
||||||
"minSendable": myextension.lnurlpayamount * 1000,
|
"myextension.api_lnurl_pay_callback", myextension_id=myextension_id
|
||||||
"metadata":"[[\"text/plain\", \"" + myextension.name + "\"]]",
|
)
|
||||||
"tag": "payRequest"
|
),
|
||||||
}
|
"maxSendable": myextension.lnurlpayamount * 1000,
|
||||||
|
"minSendable": myextension.lnurlpayamount * 1000,
|
||||||
|
"metadata": '[["text/plain", "' + myextension.name + '"]]',
|
||||||
|
"tag": "payRequest",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get(
|
@myextension_ext.get(
|
||||||
"/api/v1/lnurl/pay/cb/{myextension_id}",
|
"/api/v1/lnurl/pay/cb/{myextension_id}",
|
||||||
status_code=HTTPStatus.OK,
|
status_code=HTTPStatus.OK,
|
||||||
name="myextension.api_lnurl_pay_callback",
|
name="myextension.api_lnurl_pay_callback",
|
||||||
)
|
)
|
||||||
|
|
@ -53,27 +59,25 @@ async def api_lnurl_pay_cb(
|
||||||
logger.debug(myextension)
|
logger.debug(myextension)
|
||||||
if not myextension:
|
if not myextension:
|
||||||
return {"status": "ERROR", "reason": "No myextension found"}
|
return {"status": "ERROR", "reason": "No myextension found"}
|
||||||
|
|
||||||
payment_hash, payment_request = await create_invoice(
|
payment_hash, payment_request = await create_invoice(
|
||||||
wallet_id=myextension.wallet,
|
wallet_id=myextension.wallet,
|
||||||
amount=int(amount / 1000),
|
amount=int(amount / 1000),
|
||||||
memo=myextension.name,
|
memo=myextension.name,
|
||||||
unhashed_description=f"[[\"text/plain\", \"{myextension.name}\"]]".encode(),
|
unhashed_description=f'[["text/plain", "{myextension.name}"]]'.encode(),
|
||||||
extra= {
|
extra={
|
||||||
"tag": "MyExtension",
|
"tag": "MyExtension",
|
||||||
"myextensionId": myextension_id,
|
"myextensionId": myextension_id,
|
||||||
"extra": request.query_params.get("amount"),
|
"extra": request.query_params.get("amount"),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"pr": payment_request,
|
"pr": payment_request,
|
||||||
"routes": [],
|
"routes": [],
|
||||||
"successAction": {
|
"successAction": {"tag": "message", "message": f"Paid {myextension.name}"},
|
||||||
"tag": "message",
|
|
||||||
"message": f"Paid {myextension.name}"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
######## A very simple LNURLwithdraw ############
|
######## A very simple LNURLwithdraw ############
|
||||||
# https://github.com/lnurl/luds/blob/luds/03.md #
|
# 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 {"status": "ERROR", "reason": "LNURLw already used"}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"tag": "withdrawRequest",
|
"tag": "withdrawRequest",
|
||||||
"callback": str(request.url_for("myextension.api_lnurl_withdraw_callback", myextension_id=myextension_id)),
|
"callback": str(
|
||||||
"k1": k1,
|
request.url_for(
|
||||||
"defaultDescription": myextension.name,
|
"myextension.api_lnurl_withdraw_callback", myextension_id=myextension_id
|
||||||
"maxWithdrawable": myextension.lnurlwithdrawamount * 1000,
|
)
|
||||||
"minWithdrawable": myextension.lnurlwithdrawamount * 1000
|
),
|
||||||
}
|
"k1": k1,
|
||||||
|
"defaultDescription": myextension.name,
|
||||||
|
"maxWithdrawable": myextension.lnurlwithdrawamount * 1000,
|
||||||
|
"minWithdrawable": myextension.lnurlwithdrawamount * 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get(
|
@myextension_ext.get(
|
||||||
"/api/v1/lnurl/withdraw/cb/{myextension_id}",
|
"/api/v1/lnurl/withdraw/cb/{myextension_id}",
|
||||||
status_code=HTTPStatus.OK,
|
status_code=HTTPStatus.OK,
|
||||||
name="myextension.api_lnurl_withdraw_callback",
|
name="myextension.api_lnurl_withdraw_callback",
|
||||||
)
|
)
|
||||||
|
|
@ -125,12 +134,14 @@ async def api_lnurl_withdraw_cb(
|
||||||
myextension = await get_myextension(myextension_id)
|
myextension = await get_myextension(myextension_id)
|
||||||
if not myextension:
|
if not myextension:
|
||||||
return {"status": "ERROR", "reason": "No myextension found"}
|
return {"status": "ERROR", "reason": "No myextension found"}
|
||||||
|
|
||||||
k1Check = shortuuid.uuid(name=myextension.id + str(myextension.ticker))
|
k1Check = shortuuid.uuid(name=myextension.id + str(myextension.ticker))
|
||||||
if k1Check != k1:
|
if k1Check != k1:
|
||||||
return {"status": "ERROR", "reason": "Wrong k1 check provided"}
|
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(myextension.wallet)
|
||||||
logger.debug(pr)
|
logger.debug(pr)
|
||||||
logger.debug(int(myextension.lnurlwithdrawamount * 1000))
|
logger.debug(int(myextension.lnurlwithdrawamount * 1000))
|
||||||
|
|
@ -138,6 +149,10 @@ async def api_lnurl_withdraw_cb(
|
||||||
wallet_id=myextension.wallet,
|
wallet_id=myextension.wallet,
|
||||||
payment_request=pr,
|
payment_request=pr,
|
||||||
max_sat=int(myextension.lnurlwithdrawamount * 1000),
|
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"}
|
return {"status": "OK"}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
# The migration file is like a blockchain, never edit only add!
|
# The migration file is like a blockchain, never edit only add!
|
||||||
|
|
||||||
|
|
||||||
async def m001_initial(db):
|
async def m001_initial(db):
|
||||||
"""
|
"""
|
||||||
Initial templates table.
|
Initial templates table.
|
||||||
|
|
@ -19,8 +20,10 @@ async def m001_initial(db):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Here we add another field to the database
|
# Here we add another field to the database
|
||||||
|
|
||||||
|
|
||||||
async def m002_addtip_wallet(db):
|
async def m002_addtip_wallet(db):
|
||||||
"""
|
"""
|
||||||
Add total to templates table
|
Add total to templates table
|
||||||
|
|
@ -29,4 +32,4 @@ async def m002_addtip_wallet(db):
|
||||||
"""
|
"""
|
||||||
ALTER TABLE myextension.maintable ADD ticker INTEGER DEFAULT 1;
|
ALTER TABLE myextension.maintable ADD ticker INTEGER DEFAULT 1;
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from fastapi import Request
|
||||||
from lnbits.lnurl import encode as lnurl_encode
|
from lnbits.lnurl import encode as lnurl_encode
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
class CreateMyExtensionData(BaseModel):
|
class CreateMyExtensionData(BaseModel):
|
||||||
wallet: Optional[str]
|
wallet: Optional[str]
|
||||||
name: Optional[str]
|
name: Optional[str]
|
||||||
|
|
@ -17,6 +18,7 @@ class CreateMyExtensionData(BaseModel):
|
||||||
lnurlwithdrawamount: Optional[int]
|
lnurlwithdrawamount: Optional[int]
|
||||||
ticker: Optional[int]
|
ticker: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class MyExtension(BaseModel):
|
class MyExtension(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: Optional[str]
|
wallet: Optional[str]
|
||||||
|
|
@ -30,4 +32,4 @@ class MyExtension(BaseModel):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "MyExtension":
|
def from_row(cls, row: Row) -> "MyExtension":
|
||||||
return cls(**dict(row))
|
return cls(**dict(row))
|
||||||
|
|
|
||||||
11
tasks.py
11
tasks.py
|
|
@ -29,6 +29,7 @@ async def wait_for_paid_invoices():
|
||||||
|
|
||||||
# do somethhing when an invoice related top this extension is paid
|
# do somethhing when an invoice related top this extension is paid
|
||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
logger.debug("payment received for myextension extension")
|
logger.debug("payment received for myextension extension")
|
||||||
if payment.extra.get("tag") != "MyExtension":
|
if payment.extra.get("tag") != "MyExtension":
|
||||||
|
|
@ -42,20 +43,18 @@ async def on_invoice_paid(payment: Payment) -> None:
|
||||||
total = myextension.total - payment.amount
|
total = myextension.total - payment.amount
|
||||||
else:
|
else:
|
||||||
total = myextension.total + payment.amount
|
total = myextension.total + payment.amount
|
||||||
data_to_update = {
|
data_to_update = {"total": total}
|
||||||
"total": total
|
|
||||||
}
|
|
||||||
|
|
||||||
await update_myextension(myextension_id=myextension_id, **data_to_update)
|
await update_myextension(myextension_id=myextension_id, **data_to_update)
|
||||||
|
|
||||||
# here we could send some data to a websocket on wss://<your-lnbits>/api/v1/ws/<myextension_id>
|
# here we could send some data to a websocket on wss://<your-lnbits>/api/v1/ws/<myextension_id>
|
||||||
# and then listen to it on the frontend, which we do with index.html connectWebocket()
|
# and then listen to it on the frontend, which we do with index.html connectWebocket()
|
||||||
|
|
||||||
some_payment_data = {
|
some_payment_data = {
|
||||||
"name": myextension.name,
|
"name": myextension.name,
|
||||||
"amount": payment.amount,
|
"amount": payment.amount,
|
||||||
"fee": payment.fee,
|
"fee": payment.fee,
|
||||||
"checking_id": payment.checking_id
|
"checking_id": payment.checking_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
await websocketUpdater(myextension_id, str(some_payment_data))
|
await websocketUpdater(myextension_id, str(some_payment_data))
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
<q-expansion-item
|
<q-expansion-item group="extras" icon="swap_vertical_circle" label="API info" :content-inset-level="0.5">
|
||||||
group="extras"
|
|
||||||
icon="swap_vertical_circle"
|
|
||||||
label="API info"
|
|
||||||
:content-inset-level="0.5"
|
|
||||||
>
|
|
||||||
<q-btn flat label="Swagger API" type="a" href="../docs#/MyExtension"></q-btn>
|
<q-btn flat label="Swagger API" type="a" href="../docs#/MyExtension"></q-btn>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
@ -4,24 +4,10 @@
|
||||||
<p>
|
<p>
|
||||||
Some more info about my excellent extension.
|
Some more info about my excellent extension.
|
||||||
</p>
|
</p>
|
||||||
<small
|
<small>Created by
|
||||||
>Created by
|
<a class="text-secondary" href="https://github.com/benarc" target="_blank">Ben Arc</a>.</small>
|
||||||
<a
|
<small>Repo
|
||||||
class="text-secondary"
|
<a class="text-secondary" href="https://github.com/lnbits/myextension" target="_blank">MyExtension</a>.</small>
|
||||||
href="https://github.com/benarc"
|
|
||||||
target="_blank"
|
|
||||||
>Ben Arc</a
|
|
||||||
>.</small
|
|
||||||
>
|
|
||||||
<small
|
|
||||||
>Repo
|
|
||||||
<a
|
|
||||||
class="text-secondary"
|
|
||||||
href="https://github.com/lnbits/myextension"
|
|
||||||
target="_blank"
|
|
||||||
>MyExtension</a
|
|
||||||
>.</small
|
|
||||||
>
|
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-expansion-item>
|
</q-expansion-item>
|
||||||
|
|
@ -4,10 +4,8 @@
|
||||||
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
<div class="col-12 col-md-8 col-lg-7 q-gutter-y-md">
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<q-btn unelevated color="primary" @click="formDialog.show = true"
|
<q-btn unelevated color="primary" @click="formDialog.show = true">New MyExtension</q-btn>
|
||||||
>New MyExtension</q-btn
|
</q-card-section>
|
||||||
>
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
<q-card>
|
<q-card>
|
||||||
|
|
@ -20,14 +18,8 @@
|
||||||
<q-btn flat color="grey" @click="exportCSV">Export to CSV</q-btn>
|
<q-btn flat color="grey" @click="exportCSV">Export to CSV</q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<q-table
|
<q-table dense flat :data="temps" row-key="id" :columns="tempsTable.columns"
|
||||||
dense
|
:pagination.sync="tempsTable.pagination">
|
||||||
flat
|
|
||||||
:data="temps"
|
|
||||||
row-key="id"
|
|
||||||
:columns="tempsTable.columns"
|
|
||||||
:pagination.sync="tempsTable.pagination"
|
|
||||||
>
|
|
||||||
<myextension v-slot:header="props">
|
<myextension v-slot:header="props">
|
||||||
<q-tr :props="props">
|
<q-tr :props="props">
|
||||||
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
<q-th v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
|
|
@ -38,63 +30,30 @@
|
||||||
|
|
||||||
<template v-slot:body="props">
|
<template v-slot:body="props">
|
||||||
<q-tr :props="props">
|
<q-tr :props="props">
|
||||||
<q-td
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||||
v-for="col in props.cols"
|
<div v-if="col.field == 'total'">${ col.value / 1000} sats</div>
|
||||||
:key="col.name"
|
<div v-else>${ col.value }</div>
|
||||||
:props="props"
|
</q-td>
|
||||||
>
|
<q-td auto-width>
|
||||||
<div v-if="col.field == 'total'">${ col.value / 1000} sats</div>
|
<q-btn unelevated dense size="sm" icon="qr_code" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||||
<div v-else>${ col.value }</div>
|
class="q-mr-sm" @click="openUrlDialog(props.row.id)"></q-btn></q-td>
|
||||||
</q-td>
|
<q-td auto-width>
|
||||||
<q-td auto-width>
|
<q-btn unelevated dense size="sm" icon="launch" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||||
<q-btn
|
type="a" :href="props.row.myextension" target="_blank"><q-tooltip>Open public
|
||||||
unelevated
|
page</q-tooltip></q-btn></q-td>
|
||||||
dense
|
|
||||||
size="sm"
|
|
||||||
icon="qr_code"
|
|
||||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
|
||||||
class="q-mr-sm"
|
|
||||||
@click="openUrlDialog(props.row.id)"
|
|
||||||
></q-btn></q-td>
|
|
||||||
<q-td auto-width>
|
|
||||||
<q-btn
|
|
||||||
unelevated
|
|
||||||
dense
|
|
||||||
size="sm"
|
|
||||||
icon="launch"
|
|
||||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
|
||||||
type="a"
|
|
||||||
:href="props.row.myextension"
|
|
||||||
target="_blank"
|
|
||||||
><q-tooltip>Open public page</q-tooltip></q-btn
|
|
||||||
></q-td>
|
|
||||||
|
|
||||||
<q-td>
|
<q-td>
|
||||||
<q-btn
|
<q-btn flat dense size="xs" @click="updateMyExtensionForm(props.row.id)" icon="edit" color="light-blue">
|
||||||
flat
|
<q-tooltip> Edit copilot </q-tooltip>
|
||||||
dense
|
</q-btn>
|
||||||
size="xs"
|
</q-td>
|
||||||
@click="updateMyExtensionForm(props.row.id)"
|
|
||||||
icon="edit"
|
<q-td>
|
||||||
color="light-blue"
|
<q-btn flat dense size="xs" @click="deleteMyExtension(props.row.id)" icon="cancel" color="pink">
|
||||||
>
|
<q-tooltip> Delete copilot </q-tooltip>
|
||||||
<q-tooltip> Edit copilot </q-tooltip>
|
</q-btn>
|
||||||
</q-btn>
|
</q-td>
|
||||||
</q-td>
|
|
||||||
|
|
||||||
<q-td>
|
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
size="xs"
|
|
||||||
@click="deleteMyExtension(props.row.id)"
|
|
||||||
icon="cancel"
|
|
||||||
color="pink"
|
|
||||||
>
|
|
||||||
<q-tooltip> Delete copilot </q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</q-td>
|
|
||||||
|
|
||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -107,7 +66,8 @@
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<h6 class="text-subtitle1 q-my-none">{{SITE_TITLE}} MyExtension extension</h6>
|
<h6 class="text-subtitle1 q-my-none">{{SITE_TITLE}} MyExtension extension</h6>
|
||||||
<p>Simple extension you can use as a base for your own extension. <br/> Includes very simple LNURL-pay and LNURL-withdraw example.</p>
|
<p>Simple extension you can use as a base for your own extension. <br /> Includes very simple LNURL-pay and
|
||||||
|
LNURL-withdraw example.</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<q-separator></q-separator>
|
<q-separator></q-separator>
|
||||||
|
|
@ -123,54 +83,20 @@
|
||||||
<q-dialog v-model="formDialog.show" position="top" @hide="closeFormDialog">
|
<q-dialog v-model="formDialog.show" position="top" @hide="closeFormDialog">
|
||||||
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||||
<q-form @submit="sendMyExtensionData" class="q-gutter-md">
|
<q-form @submit="sendMyExtensionData" class="q-gutter-md">
|
||||||
<q-input
|
<q-input filled dense v-model.trim="formDialog.data.name" label="Name"
|
||||||
filled
|
placeholder="Name for your record"></q-input>
|
||||||
dense
|
<q-select filled dense emit-value v-model="formDialog.data.wallet" :options="g.user.walletOptions"
|
||||||
v-model.trim="formDialog.data.name"
|
label="Wallet *"></q-select>
|
||||||
label="Name"
|
<q-input filled dense type="number" v-model.trim="formDialog.data.lnurlwithdrawamount"
|
||||||
placeholder="Name for your record"
|
label="LNURL-withdraw amount"></q-input>
|
||||||
></q-input>
|
<q-input filled dense type="number" v-model.trim="formDialog.data.lnurlpayamount"
|
||||||
<q-select
|
label="LNURL-pay amount"></q-input>
|
||||||
filled
|
|
||||||
dense
|
|
||||||
emit-value
|
|
||||||
v-model="formDialog.data.wallet"
|
|
||||||
:options="g.user.walletOptions"
|
|
||||||
label="Wallet *"
|
|
||||||
></q-select>
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
type="number"
|
|
||||||
v-model.trim="formDialog.data.lnurlwithdrawamount"
|
|
||||||
label="LNURL-withdraw amount"
|
|
||||||
></q-input>
|
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
type="number"
|
|
||||||
v-model.trim="formDialog.data.lnurlpayamount"
|
|
||||||
label="LNURL-pay amount"
|
|
||||||
></q-input>
|
|
||||||
<div class="row q-mt-lg">
|
<div class="row q-mt-lg">
|
||||||
<q-btn
|
<q-btn v-if="formDialog.data.id" unelevated color="primary" type="submit">Update MyExtension</q-btn>
|
||||||
v-if="formDialog.data.id"
|
<q-btn v-else unelevated color="primary"
|
||||||
unelevated
|
|
||||||
color="primary"
|
|
||||||
type="submit"
|
|
||||||
>Update MyExtension</q-btn
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
v-else
|
|
||||||
unelevated
|
|
||||||
color="primary"
|
|
||||||
:disable="formDialog.data.name == null || formDialog.data.wallet == null || formDialog.data.lnurlwithdrawamount == null || formDialog.data.lnurlpayamount == null"
|
:disable="formDialog.data.name == null || formDialog.data.wallet == null || formDialog.data.lnurlwithdrawamount == null || formDialog.data.lnurlpayamount == null"
|
||||||
type="submit"
|
type="submit">Create MyExtension</q-btn>
|
||||||
>Create MyExtension</q-btn
|
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||||
>
|
|
||||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
|
||||||
>Cancel</q-btn
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</q-form>
|
</q-form>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
@ -178,31 +104,30 @@
|
||||||
|
|
||||||
<q-dialog v-model="urlDialog.show" position="top">
|
<q-dialog v-model="urlDialog.show" position="top">
|
||||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||||
|
|
||||||
|
|
||||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||||
<lnbits-qrcode
|
<lnbits-qrcode :value="qrValue"></lnbits-qrcode>
|
||||||
:value="qrValue"
|
</q-responsive>
|
||||||
></lnbits-qrcode>
|
<center><q-btn label="copy" @click="copyText(qrValue)"></q-btn>
|
||||||
</q-responsive>
|
</center>
|
||||||
<center><q-btn label="copy" @click="copyText(qrValue)"></q-btn>
|
|
||||||
</center>
|
|
||||||
|
|
||||||
<q-separator></q-separator>
|
<q-separator></q-separator>
|
||||||
|
|
||||||
<div class="row justify-start q-mt-lg">
|
<div class="row justify-start q-mt-lg">
|
||||||
<div class="col col-md-auto">
|
<div class="col col-md-auto">
|
||||||
<q-btn outline style="color: primmary;" @click="qrValue = urlDialog.data.lnurlpay">lnurlpay</q-btn>
|
<q-btn outline style="color: primmary;" @click="qrValue = urlDialog.data.lnurlpay">lnurlpay</q-btn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-auto">
|
<div class="col col-md-auto">
|
||||||
<q-btn outline style="color: primmary;" @click="qrValue = urlDialog.data.lnurlwithdraw">lnurlwithdraw</q-btn>
|
<q-btn outline style="color: primmary;" @click="qrValue = urlDialog.data.lnurlwithdraw">lnurlwithdraw</q-btn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col q-pl-md">
|
<div class="col q-pl-md">
|
||||||
<q-input filled bottom-slots dense v-model="invoiceAmount">
|
<q-input filled bottom-slots dense v-model="invoiceAmount">
|
||||||
<template v-slot:append>
|
<template v-slot:append>
|
||||||
<q-btn round @click="createInvoice(urlDialog.data.wallet, urlDialog.data.id)" color="primary" flat icon="add_circle" />
|
<q-btn round @click="createInvoice(urlDialog.data.wallet, urlDialog.data.id)" color="primary" flat
|
||||||
|
icon="add_circle" />
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:hint>
|
<template v-slot:hint>
|
||||||
Create an invoice
|
Create an invoice
|
||||||
|
|
@ -213,7 +138,7 @@
|
||||||
|
|
||||||
|
|
||||||
<div class="row q-mt-lg">
|
<div class="row q-mt-lg">
|
||||||
|
|
||||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
|
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
|
||||||
</div>
|
</div>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
@ -242,15 +167,15 @@
|
||||||
temps: [],
|
temps: [],
|
||||||
tempsTable: {
|
tempsTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{name: 'id', align: 'left', label: 'ID', field: 'id'},
|
{ name: 'id', align: 'left', label: 'ID', field: 'id' },
|
||||||
{name: 'name', align: 'left', label: 'Name', field: 'name'},
|
{ name: 'name', align: 'left', label: 'Name', field: 'name' },
|
||||||
{
|
{
|
||||||
name: 'wallet',
|
name: 'wallet',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: 'Wallet',
|
label: 'Wallet',
|
||||||
field: 'wallet'
|
field: 'wallet'
|
||||||
},
|
},
|
||||||
{name: 'total', align: 'left', label: 'Total sent/received', field: 'total'},
|
{ name: 'total', align: 'left', label: 'Total sent/received', field: 'total' },
|
||||||
],
|
],
|
||||||
pagination: {
|
pagination: {
|
||||||
rowsPerPage: 10
|
rowsPerPage: 10
|
||||||
|
|
@ -317,7 +242,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateMyExtensionForm(tempId) {
|
updateMyExtensionForm(tempId) {
|
||||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
const myextension = _.findWhere(this.temps, { id: tempId })
|
||||||
this.formDialog.data = {
|
this.formDialog.data = {
|
||||||
...myextension
|
...myextension
|
||||||
}
|
}
|
||||||
|
|
@ -361,7 +286,7 @@
|
||||||
},
|
},
|
||||||
deleteMyExtension: function (tempId) {
|
deleteMyExtension: function (tempId) {
|
||||||
var self = this
|
var self = this
|
||||||
var myextension = _.findWhere(this.temps, {id: tempId})
|
var myextension = _.findWhere(this.temps, { id: tempId })
|
||||||
|
|
||||||
LNbits.utils
|
LNbits.utils
|
||||||
.confirmDialog('Are you sure you want to delete this MyExtension?')
|
.confirmDialog('Are you sure you want to delete this MyExtension?')
|
||||||
|
|
@ -370,7 +295,7 @@
|
||||||
.request(
|
.request(
|
||||||
'DELETE',
|
'DELETE',
|
||||||
'/myextension/api/v1/temps/' + tempId,
|
'/myextension/api/v1/temps/' + tempId,
|
||||||
_.findWhere(self.g.user.wallets, {id: myextension.wallet}).adminkey
|
_.findWhere(self.g.user.wallets, { id: myextension.wallet }).adminkey
|
||||||
)
|
)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
self.temps = _.reject(self.temps, function (obj) {
|
self.temps = _.reject(self.temps, function (obj) {
|
||||||
|
|
@ -386,17 +311,17 @@
|
||||||
LNbits.utils.exportCSV(this.tempsTable.columns, this.temps)
|
LNbits.utils.exportCSV(this.tempsTable.columns, this.temps)
|
||||||
},
|
},
|
||||||
itemsArray(tempId) {
|
itemsArray(tempId) {
|
||||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
const myextension = _.findWhere(this.temps, { id: tempId })
|
||||||
return [...myextension.itemsMap.values()]
|
return [...myextension.itemsMap.values()]
|
||||||
},
|
},
|
||||||
itemFormatPrice(price, id) {
|
itemFormatPrice(price, id) {
|
||||||
const myextension = id.split(':')[0]
|
const myextension = id.split(':')[0]
|
||||||
const currency = _.findWhere(this.temps, {id: myextension}).currency
|
const currency = _.findWhere(this.temps, { id: myextension }).currency
|
||||||
return LNbits.utils.formatCurrency(Number(price).toFixed(2), currency)
|
return LNbits.utils.formatCurrency(Number(price).toFixed(2), currency)
|
||||||
},
|
},
|
||||||
openformDialog(id) {
|
openformDialog(id) {
|
||||||
const [tempId, itemId] = id.split(':')
|
const [tempId, itemId] = id.split(':')
|
||||||
const myextension = _.findWhere(this.temps, {id: tempId})
|
const myextension = _.findWhere(this.temps, { id: tempId })
|
||||||
if (itemId) {
|
if (itemId) {
|
||||||
const item = myextension.itemsMap.get(id)
|
const item = myextension.itemsMap.get(id)
|
||||||
this.formDialog.data = {
|
this.formDialog.data = {
|
||||||
|
|
@ -419,16 +344,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
openUrlDialog(id) {
|
openUrlDialog(id) {
|
||||||
this.urlDialog.data = _.findWhere(this.temps, {id})
|
this.urlDialog.data = _.findWhere(this.temps, { id })
|
||||||
this.qrValue = this.urlDialog.data.lnurlpay
|
this.qrValue = this.urlDialog.data.lnurlpay
|
||||||
console.log(this.urlDialog.data.id)
|
console.log(this.urlDialog.data.id)
|
||||||
this.connectWebocket(this.urlDialog.data.id)
|
this.connectWebocket(this.urlDialog.data.id)
|
||||||
this.urlDialog.show = true
|
this.urlDialog.show = true
|
||||||
},
|
},
|
||||||
createInvoice(walletId, myextensionId) {
|
createInvoice(walletId, myextensionId) {
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
///Simple call to the api to create an invoice/////
|
///Simple call to the api to create an invoice/////
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
console.log(walletId)
|
console.log(walletId)
|
||||||
const wallet = _.findWhere(this.g.user.wallets, {
|
const wallet = _.findWhere(this.g.user.wallets, {
|
||||||
id: walletId
|
id: walletId
|
||||||
|
|
@ -486,32 +411,32 @@
|
||||||
}
|
}
|
||||||
frame()
|
frame()
|
||||||
},
|
},
|
||||||
connectWebocket(id){
|
connectWebocket(id) {
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
///wait for pay action to happen and do a thing////
|
///wait for pay action to happen and do a thing////
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
self = this
|
self = this
|
||||||
if (location.protocol !== 'http:') {
|
if (location.protocol !== 'http:') {
|
||||||
localUrl =
|
localUrl =
|
||||||
'wss://' +
|
'wss://' +
|
||||||
document.domain +
|
document.domain +
|
||||||
':' +
|
':' +
|
||||||
location.port +
|
location.port +
|
||||||
'/api/v1/ws/' +
|
'/api/v1/ws/' +
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
localUrl =
|
localUrl =
|
||||||
'ws://' +
|
'ws://' +
|
||||||
document.domain +
|
document.domain +
|
||||||
':' +
|
':' +
|
||||||
location.port +
|
location.port +
|
||||||
'/api/v1/ws/' +
|
'/api/v1/ws/' +
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
this.connection = new WebSocket(localUrl)
|
this.connection = new WebSocket(localUrl)
|
||||||
this.connection.onmessage = function (e) {
|
this.connection.onmessage = function (e) {
|
||||||
self.makeItRain()
|
self.makeItRain()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
|
|
@ -521,4 +446,4 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
@ -6,29 +6,23 @@
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<a class="text-secondary" href="lightning:{{ lnurl }}">
|
<a class="text-secondary" href="lightning:{{ lnurl }}">
|
||||||
<q-responsive :ratio="1" class="q-mx-md">
|
<q-responsive :ratio="1" class="q-mx-md">
|
||||||
<qrcode
|
<qrcode :value="qrValue" :options="{width: 800}" class="rounded-borders"></qrcode>
|
||||||
:value="qrValue"
|
|
||||||
:options="{width: 800}"
|
|
||||||
class="rounded-borders"
|
|
||||||
></qrcode>
|
|
||||||
</q-responsive>
|
</q-responsive>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="row q-mt-lg q-gutter-sm">
|
<div class="row q-mt-lg q-gutter-sm">
|
||||||
<q-btn outline color="grey" @click="copyText(qrValue)"
|
<q-btn outline color="grey" @click="copyText(qrValue)">Copy LNURL </q-btn>
|
||||||
>Copy LNURL </q-btn
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<div class="row justify-start q-mt-lg">
|
<div class="row justify-start q-mt-lg">
|
||||||
<div class="col col-md-auto">
|
<div class="col col-md-auto">
|
||||||
<q-btn outline style="color: primmary;" @click="qrValue = '{{ lnurlpay }}'">lnurlpay</q-btn>
|
<q-btn outline style="color: primmary;" @click="qrValue = '{{ lnurlpay }}'">lnurlpay</q-btn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-auto">
|
<div class="col col-md-auto">
|
||||||
<q-btn outline style="color: primmary;" @click="qrValue = '{{ lnurlwithdraw }}'">lnurlwithdraw</q-btn>
|
<q-btn outline style="color: primmary;" @click="qrValue = '{{ lnurlwithdraw }}'">lnurlwithdraw</q-btn>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -40,15 +34,15 @@
|
||||||
<h6 class="text-subtitle1 q-mb-sm q-mt-none">Public page</h6>
|
<h6 class="text-subtitle1 q-mb-sm q-mt-none">Public page</h6>
|
||||||
<p class="q-my-none">
|
<p class="q-my-none">
|
||||||
Moat extensions have a public page that can be shared
|
Moat extensions have a public page that can be shared
|
||||||
(this page will still be accessible even if you have restricted
|
(this page will still be accessible even if you have restricted
|
||||||
access to your LNbits install).
|
access to your LNbits install).
|
||||||
<br/>
|
<br />
|
||||||
In this example when a user pays the LNURLpay it triggers an event via a websocket waiting for the payment.
|
In this example when a user pays the LNURLpay it triggers an event via a websocket waiting for the payment.
|
||||||
</p>.</p>
|
</p>.</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
<q-separator></q-separator>
|
<q-separator></q-separator>
|
||||||
<q-list> </q-list>
|
<q-list> </q-list>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -102,34 +96,34 @@
|
||||||
}
|
}
|
||||||
frame()
|
frame()
|
||||||
},
|
},
|
||||||
connectWebocket(id){
|
connectWebocket(id) {
|
||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
///wait for pay action to happen and do a thing////
|
///wait for pay action to happen and do a thing////
|
||||||
///////////////////////////////////////////////////
|
///////////////////////////////////////////////////
|
||||||
self = this
|
self = this
|
||||||
if (location.protocol !== 'http:') {
|
if (location.protocol !== 'http:') {
|
||||||
localUrl =
|
localUrl =
|
||||||
'wss://' +
|
'wss://' +
|
||||||
document.domain +
|
document.domain +
|
||||||
':' +
|
':' +
|
||||||
location.port +
|
location.port +
|
||||||
'/api/v1/ws/' +
|
'/api/v1/ws/' +
|
||||||
id
|
id
|
||||||
} else {
|
} else {
|
||||||
localUrl =
|
localUrl =
|
||||||
'ws://' +
|
'ws://' +
|
||||||
document.domain +
|
document.domain +
|
||||||
':' +
|
':' +
|
||||||
location.port +
|
location.port +
|
||||||
'/api/v1/ws/' +
|
'/api/v1/ws/' +
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
this.connection = new WebSocket(localUrl)
|
this.connection = new WebSocket(localUrl)
|
||||||
this.connection.onmessage = function (e) {
|
this.connection.onmessage = function (e) {
|
||||||
self.makeItRain()
|
self.makeItRain()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
7
views.py
7
views.py
|
|
@ -22,6 +22,7 @@ temps = Jinja2Templates(directory="temps")
|
||||||
|
|
||||||
# Backend admin page
|
# Backend admin page
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get("/", response_class=HTMLResponse)
|
@myextension_ext.get("/", response_class=HTMLResponse)
|
||||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return myextension_renderer().TemplateResponse(
|
return myextension_renderer().TemplateResponse(
|
||||||
|
|
@ -31,6 +32,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
|
|
||||||
# Frontend shareable page
|
# Frontend shareable page
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get("/{myextension_id}")
|
@myextension_ext.get("/{myextension_id}")
|
||||||
async def myextension(request: Request, myextension_id):
|
async def myextension(request: Request, myextension_id):
|
||||||
myextension = await get_myextension(myextension_id, request)
|
myextension = await get_myextension(myextension_id, request)
|
||||||
|
|
@ -52,9 +54,10 @@ async def myextension(request: Request, myextension_id):
|
||||||
|
|
||||||
# Manifest for public page, customise or remove manifest completely
|
# Manifest for public page, customise or remove manifest completely
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get("/manifest/{myextension_id}.webmanifest")
|
@myextension_ext.get("/manifest/{myextension_id}.webmanifest")
|
||||||
async def manifest(myextension_id: str):
|
async def manifest(myextension_id: str):
|
||||||
myextension= await get_myextension(myextension_id)
|
myextension = await get_myextension(myextension_id)
|
||||||
if not myextension:
|
if not myextension:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="MyExtension does not exist."
|
status_code=HTTPStatus.NOT_FOUND, detail="MyExtension does not exist."
|
||||||
|
|
@ -86,4 +89,4 @@ async def manifest(myextension_id: str):
|
||||||
"url": "/myextension/" + myextension_id,
|
"url": "/myextension/" + myextension_id,
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
53
views_api.py
53
views_api.py
|
|
@ -25,7 +25,7 @@ from .crud import (
|
||||||
update_myextension,
|
update_myextension,
|
||||||
delete_myextension,
|
delete_myextension,
|
||||||
get_myextension,
|
get_myextension,
|
||||||
get_myextensions
|
get_myextensions,
|
||||||
)
|
)
|
||||||
from .models import CreateMyExtensionData
|
from .models import CreateMyExtensionData
|
||||||
|
|
||||||
|
|
@ -36,25 +36,29 @@ from .models import CreateMyExtensionData
|
||||||
|
|
||||||
## Get all the records belonging to the user
|
## Get all the records belonging to the user
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get("/api/v1/temps", status_code=HTTPStatus.OK)
|
@myextension_ext.get("/api/v1/temps", status_code=HTTPStatus.OK)
|
||||||
async def api_myextensions(
|
async def api_myextensions(
|
||||||
req: Request, all_wallets:
|
req: Request,
|
||||||
bool = Query(False),
|
all_wallets: bool = Query(False),
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type)
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
):
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
user = await get_user(wallet.wallet.user)
|
user = await get_user(wallet.wallet.user)
|
||||||
wallet_ids = user.wallet_ids if user else []
|
wallet_ids = user.wallet_ids if user else []
|
||||||
return [myextension.dict() for myextension in await get_myextensions(wallet_ids, req)]
|
return [
|
||||||
|
myextension.dict() for myextension in await get_myextensions(wallet_ids, req)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
## Get a single record
|
## Get a single record
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.get("/api/v1/temps/{myextension_id}", status_code=HTTPStatus.OK)
|
@myextension_ext.get("/api/v1/temps/{myextension_id}", status_code=HTTPStatus.OK)
|
||||||
async def api_myextension(
|
async def api_myextension(
|
||||||
req: Request,
|
req: Request, myextension_id: str, WalletTypeInfo=Depends(get_key_type)
|
||||||
myextension_id: str,
|
):
|
||||||
WalletTypeInfo = Depends(get_key_type)):
|
|
||||||
myextension = await get_myextension(myextension_id, req)
|
myextension = await get_myextension(myextension_id, req)
|
||||||
if not myextension:
|
if not myextension:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
@ -62,8 +66,10 @@ async def api_myextension(
|
||||||
)
|
)
|
||||||
return myextension.dict()
|
return myextension.dict()
|
||||||
|
|
||||||
|
|
||||||
## update a record
|
## update a record
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.put("/api/v1/temps/{myextension_id}")
|
@myextension_ext.put("/api/v1/temps/{myextension_id}")
|
||||||
async def api_myextension_update(
|
async def api_myextension_update(
|
||||||
req: Request,
|
req: Request,
|
||||||
|
|
@ -79,25 +85,33 @@ async def api_myextension_update(
|
||||||
assert myextension, "MyExtension couldn't be retrieved"
|
assert myextension, "MyExtension couldn't be retrieved"
|
||||||
|
|
||||||
if wallet.wallet.id != myextension.wallet:
|
if wallet.wallet.id != myextension.wallet:
|
||||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your MyExtension.")
|
raise HTTPException(
|
||||||
myextension = await update_myextension(myextension_id=myextension_id, **data.dict(), req=req)
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your MyExtension."
|
||||||
|
)
|
||||||
|
myextension = await update_myextension(
|
||||||
|
myextension_id=myextension_id, **data.dict(), req=req
|
||||||
|
)
|
||||||
return myextension.dict()
|
return myextension.dict()
|
||||||
|
|
||||||
|
|
||||||
## Create a new record
|
## Create a new record
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.post("/api/v1/temps", status_code=HTTPStatus.CREATED)
|
@myextension_ext.post("/api/v1/temps", status_code=HTTPStatus.CREATED)
|
||||||
async def api_myextension_create(
|
async def api_myextension_create(
|
||||||
req: Request,
|
req: Request,
|
||||||
data: CreateMyExtensionData,
|
data: CreateMyExtensionData,
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type)
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
):
|
):
|
||||||
myextension = await create_myextension(wallet_id=wallet.wallet.id, data=data, req=req)
|
myextension = await create_myextension(
|
||||||
|
wallet_id=wallet.wallet.id, data=data, req=req
|
||||||
|
)
|
||||||
return myextension.dict()
|
return myextension.dict()
|
||||||
|
|
||||||
|
|
||||||
## Delete a record
|
## Delete a record
|
||||||
|
|
||||||
|
|
||||||
@myextension_ext.delete("/api/v1/temps/{myextension_id}")
|
@myextension_ext.delete("/api/v1/temps/{myextension_id}")
|
||||||
async def api_myextension_delete(
|
async def api_myextension_delete(
|
||||||
myextension_id: str, wallet: WalletTypeInfo = Depends(require_admin_key)
|
myextension_id: str, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||||
|
|
@ -110,7 +124,9 @@ async def api_myextension_delete(
|
||||||
)
|
)
|
||||||
|
|
||||||
if myextension.wallet != wallet.wallet.id:
|
if myextension.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your MyExtension.")
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your MyExtension."
|
||||||
|
)
|
||||||
|
|
||||||
await delete_myextension(myextension_id)
|
await delete_myextension(myextension_id)
|
||||||
return "", HTTPStatus.NO_CONTENT
|
return "", HTTPStatus.NO_CONTENT
|
||||||
|
|
@ -120,7 +136,10 @@ async def api_myextension_delete(
|
||||||
|
|
||||||
## This endpoint creates a payment
|
## This endpoint creates a payment
|
||||||
|
|
||||||
@myextension_ext.post("/api/v1/temps/payment/{myextension_id}", status_code=HTTPStatus.CREATED)
|
|
||||||
|
@myextension_ext.post(
|
||||||
|
"/api/v1/temps/payment/{myextension_id}", status_code=HTTPStatus.CREATED
|
||||||
|
)
|
||||||
async def api_tpos_create_invoice(
|
async def api_tpos_create_invoice(
|
||||||
myextension_id: str, amount: int = Query(..., ge=1), memo: str = ""
|
myextension_id: str, amount: int = Query(..., ge=1), memo: str = ""
|
||||||
) -> dict:
|
) -> dict:
|
||||||
|
|
@ -130,7 +149,7 @@ async def api_tpos_create_invoice(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="MyExtension does not exist."
|
status_code=HTTPStatus.NOT_FOUND, detail="MyExtension does not exist."
|
||||||
)
|
)
|
||||||
|
|
||||||
# we create a payment and add some tags, so tasks.py can grab the payment once its paid
|
# we create a payment and add some tags, so tasks.py can grab the payment once its paid
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -148,4 +167,4 @@ async def api_tpos_create_invoice(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
||||||
|
|
||||||
return {"payment_hash": payment_hash, "payment_request": payment_request}
|
return {"payment_hash": payment_hash, "payment_request": payment_request}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue