mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-24 14:51:05 +01:00
commit
e9b9197641
61 changed files with 23219 additions and 13297 deletions
|
@ -305,9 +305,7 @@ async def perform_lnurlauth(
|
||||||
|
|
||||||
|
|
||||||
async def check_invoice_status(
|
async def check_invoice_status(
|
||||||
wallet_id: str,
|
wallet_id: str, payment_hash: str, conn: Optional[Connection] = None
|
||||||
payment_hash: str,
|
|
||||||
conn: Optional[Connection] = None,
|
|
||||||
) -> PaymentStatus:
|
) -> PaymentStatus:
|
||||||
payment = await get_wallet_payment(wallet_id, payment_hash, conn=conn)
|
payment = await get_wallet_payment(wallet_id, payment_hash, conn=conn)
|
||||||
if not payment:
|
if not payment:
|
||||||
|
|
|
@ -54,10 +54,7 @@ async def api_wallet(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
"balance": wallet.wallet.balance_msat,
|
"balance": wallet.wallet.balance_msat,
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
return {
|
return {"name": wallet.wallet.name, "balance": wallet.wallet.balance_msat}
|
||||||
"name": wallet.wallet.name,
|
|
||||||
"balance": wallet.wallet.balance_msat,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@core_app.put("/api/v1/wallet/{new_name}")
|
@core_app.put("/api/v1/wallet/{new_name}")
|
||||||
|
@ -74,11 +71,7 @@ async def api_update_wallet(
|
||||||
|
|
||||||
@core_app.get("/api/v1/payments")
|
@core_app.get("/api/v1/payments")
|
||||||
async def api_payments(wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_payments(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
await get_payments(
|
await get_payments(wallet_id=wallet.wallet.id, pending=True, complete=True)
|
||||||
wallet_id=wallet.wallet.id,
|
|
||||||
pending=True,
|
|
||||||
complete=True,
|
|
||||||
)
|
|
||||||
pendingPayments = await get_payments(wallet_id=wallet.wallet.id, pending=True)
|
pendingPayments = await get_payments(wallet_id=wallet.wallet.id, pending=True)
|
||||||
for payment in pendingPayments:
|
for payment in pendingPayments:
|
||||||
await check_invoice_status(
|
await check_invoice_status(
|
||||||
|
@ -91,7 +84,7 @@ class CreateInvoiceData(BaseModel):
|
||||||
out: Optional[bool] = True
|
out: Optional[bool] = True
|
||||||
amount: int = Query(None, ge=1)
|
amount: int = Query(None, ge=1)
|
||||||
memo: str = None
|
memo: str = None
|
||||||
unit: Optional[str] = 'sat'
|
unit: Optional[str] = "sat"
|
||||||
description_hash: Optional[str] = None
|
description_hash: Optional[str] = None
|
||||||
lnurl_callback: Optional[str] = None
|
lnurl_callback: Optional[str] = None
|
||||||
lnurl_balance_check: Optional[str] = None
|
lnurl_balance_check: Optional[str] = None
|
||||||
|
@ -107,7 +100,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet):
|
||||||
else:
|
else:
|
||||||
description_hash = b""
|
description_hash = b""
|
||||||
memo = data.memo
|
memo = data.memo
|
||||||
if data.unit == 'sat':
|
if data.unit == "sat":
|
||||||
amount = data.amount
|
amount = data.amount
|
||||||
else:
|
else:
|
||||||
price_in_sats = await fiat_amount_as_satoshis(data.amount, data.unit)
|
price_in_sats = await fiat_amount_as_satoshis(data.amount, data.unit)
|
||||||
|
@ -334,8 +327,7 @@ async def api_payment(payment_hash):
|
||||||
payment = await get_standalone_payment(payment_hash)
|
payment = await get_standalone_payment(payment_hash)
|
||||||
if not payment:
|
if not payment:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Payment does not exist."
|
||||||
detail="Payment does not exist.",
|
|
||||||
)
|
)
|
||||||
elif not payment.pending:
|
elif not payment.pending:
|
||||||
return {"paid": True, "preimage": payment.preimage}
|
return {"paid": True, "preimage": payment.preimage}
|
||||||
|
|
|
@ -14,14 +14,13 @@ bleskomat_static_files = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
bleskomat_ext: APIRouter = APIRouter(
|
bleskomat_ext: APIRouter = APIRouter(prefix="/bleskomat", tags=["Bleskomat"])
|
||||||
prefix="/bleskomat",
|
|
||||||
tags=["Bleskomat"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def bleskomat_renderer():
|
def bleskomat_renderer():
|
||||||
return template_renderer(["lnbits/extensions/bleskomat/templates"])
|
return template_renderer(["lnbits/extensions/bleskomat/templates"])
|
||||||
|
|
||||||
|
|
||||||
from .lnurl_api import * # noqa
|
from .lnurl_api import * # noqa
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
from .views_api import * # noqa
|
from .views_api import * # noqa
|
||||||
|
|
|
@ -8,10 +8,7 @@ from .helpers import generate_bleskomat_lnurl_hash
|
||||||
from .models import Bleskomat, BleskomatLnurl, CreateBleskomat
|
from .models import Bleskomat, BleskomatLnurl, CreateBleskomat
|
||||||
|
|
||||||
|
|
||||||
async def create_bleskomat(
|
async def create_bleskomat(data: CreateBleskomat, wallet_id: str) -> Bleskomat:
|
||||||
data: CreateBleskomat,
|
|
||||||
wallet_id: str,
|
|
||||||
) -> Bleskomat:
|
|
||||||
bleskomat_id = uuid4().hex
|
bleskomat_id = uuid4().hex
|
||||||
api_key_id = secrets.token_hex(8)
|
api_key_id = secrets.token_hex(8)
|
||||||
api_key_secret = secrets.token_hex(32)
|
api_key_secret = secrets.token_hex(32)
|
||||||
|
|
|
@ -20,24 +20,25 @@ class CreateBleskomat(BaseModel):
|
||||||
exchange_rate_provider: str = Query(...)
|
exchange_rate_provider: str = Query(...)
|
||||||
fee: str = Query(...)
|
fee: str = Query(...)
|
||||||
|
|
||||||
@validator('fiat_currency')
|
@validator("fiat_currency")
|
||||||
def allowed_fiat_currencies(cls, v):
|
def allowed_fiat_currencies(cls, v):
|
||||||
if(v not in fiat_currencies.keys()):
|
if v not in fiat_currencies.keys():
|
||||||
raise ValueError('Not allowed currency')
|
raise ValueError("Not allowed currency")
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@validator('exchange_rate_provider')
|
@validator("exchange_rate_provider")
|
||||||
def allowed_providers(cls, v):
|
def allowed_providers(cls, v):
|
||||||
if(v not in exchange_rate_providers.keys()):
|
if v not in exchange_rate_providers.keys():
|
||||||
raise ValueError('Not allowed provider')
|
raise ValueError("Not allowed provider")
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@validator('fee')
|
@validator("fee")
|
||||||
def fee_type(cls, v):
|
def fee_type(cls, v):
|
||||||
if(not isinstance(v, (str, float, int))):
|
if not isinstance(v, (str, float, int)):
|
||||||
raise ValueError('Fee type not allowed')
|
raise ValueError("Fee type not allowed")
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
class Bleskomat(BaseModel):
|
class Bleskomat(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
@ -119,8 +120,7 @@ class BleskomatLnurl(BaseModel):
|
||||||
if tag == "withdrawRequest":
|
if tag == "withdrawRequest":
|
||||||
try:
|
try:
|
||||||
payment_hash = await pay_invoice(
|
payment_hash = await pay_invoice(
|
||||||
wallet_id=self.wallet,
|
wallet_id=self.wallet, payment_request=query["pr"]
|
||||||
payment_request=query["pr"],
|
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise LnurlValidationError("Failed to pay invoice")
|
raise LnurlValidationError("Failed to pay invoice")
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from fastapi.params import Depends
|
from fastapi.params import Depends
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
@ -22,5 +21,6 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
"fiat_currencies": fiat_currencies,
|
"fiat_currencies": fiat_currencies,
|
||||||
}
|
}
|
||||||
return bleskomat_renderer().TemplateResponse(
|
return bleskomat_renderer().TemplateResponse(
|
||||||
"bleskomat/index.html", {"request": request, "user": user.dict(), "bleskomat_vars": bleskomat_vars}
|
"bleskomat/index.html",
|
||||||
|
{"request": request, "user": user.dict(), "bleskomat_vars": bleskomat_vars},
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,10 @@ from .exchange_rates import fetch_fiat_exchange_rate
|
||||||
|
|
||||||
|
|
||||||
@bleskomat_ext.get("/api/v1/bleskomats")
|
@bleskomat_ext.get("/api/v1/bleskomats")
|
||||||
async def api_bleskomats(wallet: WalletTypeInfo = Depends(require_admin_key), all_wallets: bool = Query(False)):
|
async def api_bleskomats(
|
||||||
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
|
all_wallets: bool = Query(False),
|
||||||
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
|
@ -29,21 +32,27 @@ async def api_bleskomats(wallet: WalletTypeInfo = Depends(require_admin_key), al
|
||||||
|
|
||||||
|
|
||||||
@bleskomat_ext.get("/api/v1/bleskomat/{bleskomat_id}")
|
@bleskomat_ext.get("/api/v1/bleskomat/{bleskomat_id}")
|
||||||
async def api_bleskomat_retrieve(bleskomat_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
|
async def api_bleskomat_retrieve(
|
||||||
|
bleskomat_id, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||||
|
):
|
||||||
bleskomat = await get_bleskomat(bleskomat_id)
|
bleskomat = await get_bleskomat(bleskomat_id)
|
||||||
|
|
||||||
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND,
|
||||||
detail="Bleskomat configuration not found."
|
detail="Bleskomat configuration not found.",
|
||||||
)
|
)
|
||||||
|
|
||||||
return bleskomat.dict()
|
return bleskomat.dict()
|
||||||
|
|
||||||
|
|
||||||
@bleskomat_ext.post("/api/v1/bleskomat")
|
@bleskomat_ext.post("/api/v1/bleskomat")
|
||||||
@bleskomat_ext.put("/api/v1/bleskomat/{bleskomat_id}",)
|
@bleskomat_ext.put("/api/v1/bleskomat/{bleskomat_id}")
|
||||||
async def api_bleskomat_create_or_update(data: CreateBleskomat, wallet: WalletTypeInfo = Depends(require_admin_key), bleskomat_id=None):
|
async def api_bleskomat_create_or_update(
|
||||||
|
data: CreateBleskomat,
|
||||||
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
|
bleskomat_id=None,
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
fiat_currency = data.fiat_currency
|
fiat_currency = data.fiat_currency
|
||||||
exchange_rate_provider = data.exchange_rate_provider
|
exchange_rate_provider = data.exchange_rate_provider
|
||||||
|
@ -54,7 +63,7 @@ async def api_bleskomat_create_or_update(data: CreateBleskomat, wallet: WalletTy
|
||||||
print(e)
|
print(e)
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||||
detail=f'Failed to fetch BTC/{fiat_currency} currency pair from "{exchange_rate_provider}"'
|
detail=f'Failed to fetch BTC/{fiat_currency} currency pair from "{exchange_rate_provider}"',
|
||||||
)
|
)
|
||||||
|
|
||||||
if bleskomat_id:
|
if bleskomat_id:
|
||||||
|
@ -62,9 +71,9 @@ async def api_bleskomat_create_or_update(data: CreateBleskomat, wallet: WalletTy
|
||||||
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND,
|
||||||
detail="Bleskomat configuration not found."
|
detail="Bleskomat configuration not found.",
|
||||||
)
|
)
|
||||||
|
|
||||||
bleskomat = await update_bleskomat(bleskomat_id, **data.dict())
|
bleskomat = await update_bleskomat(bleskomat_id, **data.dict())
|
||||||
else:
|
else:
|
||||||
bleskomat = await create_bleskomat(wallet_id=wallet.wallet.id, data=data)
|
bleskomat = await create_bleskomat(wallet_id=wallet.wallet.id, data=data)
|
||||||
|
@ -73,14 +82,16 @@ async def api_bleskomat_create_or_update(data: CreateBleskomat, wallet: WalletTy
|
||||||
|
|
||||||
|
|
||||||
@bleskomat_ext.delete("/api/v1/bleskomat/{bleskomat_id}")
|
@bleskomat_ext.delete("/api/v1/bleskomat/{bleskomat_id}")
|
||||||
async def api_bleskomat_delete(bleskomat_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
|
async def api_bleskomat_delete(
|
||||||
|
bleskomat_id, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||||
|
):
|
||||||
bleskomat = await get_bleskomat(bleskomat_id)
|
bleskomat = await get_bleskomat(bleskomat_id)
|
||||||
|
|
||||||
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
if not bleskomat or bleskomat.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND,
|
||||||
detail="Bleskomat configuration not found."
|
detail="Bleskomat configuration not found.",
|
||||||
)
|
)
|
||||||
|
|
||||||
await delete_bleskomat(bleskomat_id)
|
await delete_bleskomat(bleskomat_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|
|
@ -31,4 +31,4 @@ from .views_api import * # noqa
|
||||||
|
|
||||||
def copilot_start():
|
def copilot_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))
|
||||||
|
|
|
@ -49,7 +49,7 @@ async def lnurl_callback(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found"
|
status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found"
|
||||||
)
|
)
|
||||||
amount_received = int(amount)
|
amount_received = int(amount)
|
||||||
|
|
||||||
if amount_received < 10000:
|
if amount_received < 10000:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN,
|
||||||
|
@ -80,8 +80,5 @@ async def lnurl_callback(
|
||||||
).digest(),
|
).digest(),
|
||||||
extra={"tag": "copilot", "copilotid": cp.id, "comment": comment},
|
extra={"tag": "copilot", "copilotid": cp.id, "comment": comment},
|
||||||
)
|
)
|
||||||
payResponse = {
|
payResponse = {"pr": payment_request, "routes": []}
|
||||||
"pr": payment_request,
|
|
||||||
"routes": [],
|
|
||||||
}
|
|
||||||
return json.dumps(payResponse)
|
return json.dumps(payResponse)
|
||||||
|
|
|
@ -6,13 +6,12 @@ from lnbits.helpers import template_renderer
|
||||||
db = Database("ext_events")
|
db = Database("ext_events")
|
||||||
|
|
||||||
|
|
||||||
events_ext: APIRouter = APIRouter(
|
events_ext: APIRouter = APIRouter(prefix="/events", tags=["Events"])
|
||||||
prefix="/events",
|
|
||||||
tags=["Events"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def events_renderer():
|
def events_renderer():
|
||||||
return template_renderer(["lnbits/extensions/events/templates"])
|
return template_renderer(["lnbits/extensions/events/templates"])
|
||||||
|
|
||||||
|
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
from .views_api import * # noqa
|
from .views_api import * # noqa
|
||||||
|
|
|
@ -74,6 +74,7 @@ async def get_tickets(wallet_ids: Union[str, List[str]]) -> List[Tickets]:
|
||||||
async def delete_ticket(payment_hash: str) -> None:
|
async def delete_ticket(payment_hash: str) -> None:
|
||||||
await db.execute("DELETE FROM events.ticket WHERE id = ?", (payment_hash,))
|
await db.execute("DELETE FROM events.ticket WHERE id = ?", (payment_hash,))
|
||||||
|
|
||||||
|
|
||||||
async def delete_event_tickets(event_id: str) -> None:
|
async def delete_event_tickets(event_id: str) -> None:
|
||||||
await db.execute("DELETE FROM events.tickets WHERE event = ?", (event_id,))
|
await db.execute("DELETE FROM events.tickets WHERE event = ?", (event_id,))
|
||||||
|
|
||||||
|
@ -81,9 +82,7 @@ async def delete_event_tickets(event_id: str) -> None:
|
||||||
# EVENTS
|
# EVENTS
|
||||||
|
|
||||||
|
|
||||||
async def create_event(
|
async def create_event(data: CreateEvent) -> Events:
|
||||||
data: CreateEvent
|
|
||||||
) -> Events:
|
|
||||||
event_id = urlsafe_short_hash()
|
event_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -78,14 +78,6 @@ async def m002_changed(db):
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(
|
(row[0], row[1], row[2], row[3], row[4], row[5], True),
|
||||||
row[0],
|
|
||||||
row[1],
|
|
||||||
row[2],
|
|
||||||
row[3],
|
|
||||||
row[4],
|
|
||||||
row[5],
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
await db.execute("DROP TABLE events.tickets")
|
await db.execute("DROP TABLE events.tickets")
|
||||||
|
|
|
@ -5,17 +5,19 @@ from pydantic import BaseModel
|
||||||
class CreateEvent(BaseModel):
|
class CreateEvent(BaseModel):
|
||||||
wallet: str
|
wallet: str
|
||||||
name: str
|
name: str
|
||||||
info: str
|
info: str
|
||||||
closing_date: str
|
closing_date: str
|
||||||
event_start_date: str
|
event_start_date: str
|
||||||
event_end_date: str
|
event_end_date: str
|
||||||
amount_tickets: int = Query(..., ge=0)
|
amount_tickets: int = Query(..., ge=0)
|
||||||
price_per_ticket: int = Query(..., ge=0)
|
price_per_ticket: int = Query(..., ge=0)
|
||||||
|
|
||||||
|
|
||||||
class CreateTicket(BaseModel):
|
class CreateTicket(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
email: str
|
email: str
|
||||||
|
|
||||||
|
|
||||||
class Events(BaseModel):
|
class Events(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
|
|
@ -18,7 +18,9 @@ templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
@events_ext.get("/", response_class=HTMLResponse)
|
@events_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 events_renderer().TemplateResponse("events/index.html", {"request": request, "user": user.dict()})
|
return events_renderer().TemplateResponse(
|
||||||
|
"events/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@events_ext.get("/{event_id}", response_class=HTMLResponse)
|
@events_ext.get("/{event_id}", response_class=HTMLResponse)
|
||||||
|
@ -35,8 +37,8 @@ async def display(request: Request, event_id):
|
||||||
{
|
{
|
||||||
"request": request,
|
"request": request,
|
||||||
"event_name": event.name,
|
"event_name": event.name,
|
||||||
"event_error": "Sorry, tickets are sold out :("
|
"event_error": "Sorry, tickets are sold out :(",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
datetime_object = datetime.strptime(event.closing_date, "%Y-%m-%d").date()
|
datetime_object = datetime.strptime(event.closing_date, "%Y-%m-%d").date()
|
||||||
if date.today() > datetime_object:
|
if date.today() > datetime_object:
|
||||||
|
@ -45,8 +47,8 @@ async def display(request: Request, event_id):
|
||||||
{
|
{
|
||||||
"request": request,
|
"request": request,
|
||||||
"event_name": event.name,
|
"event_name": event.name,
|
||||||
"event_error": "Sorry, ticket closing date has passed :("
|
"event_error": "Sorry, ticket closing date has passed :(",
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return events_renderer().TemplateResponse(
|
return events_renderer().TemplateResponse(
|
||||||
|
@ -57,8 +59,7 @@ async def display(request: Request, event_id):
|
||||||
"event_name": event.name,
|
"event_name": event.name,
|
||||||
"event_info": event.info,
|
"event_info": event.info,
|
||||||
"event_price": event.price_per_ticket,
|
"event_price": event.price_per_ticket,
|
||||||
}
|
},
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,8 +84,7 @@ async def ticket(request: Request, ticket_id):
|
||||||
"ticket_id": ticket_id,
|
"ticket_id": ticket_id,
|
||||||
"ticket_name": event.name,
|
"ticket_name": event.name,
|
||||||
"ticket_info": event.info,
|
"ticket_info": event.info,
|
||||||
|
},
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,5 +103,5 @@ async def register(request: Request, event_id):
|
||||||
"event_id": event_id,
|
"event_id": event_id,
|
||||||
"event_name": event.name,
|
"event_name": event.name,
|
||||||
"wallet_id": event.wallet,
|
"wallet_id": event.wallet,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,10 +5,8 @@ from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_hivemind")
|
db = Database("ext_hivemind")
|
||||||
|
|
||||||
hivemind_ext: APIRouter = APIRouter(
|
hivemind_ext: APIRouter = APIRouter(prefix="/hivemind", tags=["hivemind"])
|
||||||
prefix="/hivemind",
|
|
||||||
tags=["hivemind"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def hivemind_renderer():
|
def hivemind_renderer():
|
||||||
return template_renderer(["lnbits/extensions/hivemind/templates"])
|
return template_renderer(["lnbits/extensions/hivemind/templates"])
|
||||||
|
|
|
@ -10,4 +10,6 @@ from . import hivemind_ext, hivemind_renderer
|
||||||
|
|
||||||
@hivemind_ext.get("/", response_class=HTMLResponse)
|
@hivemind_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 hivemind_renderer().TemplateResponse("hivemind/index.html", {"request": request, "user": user.dict()})
|
return hivemind_renderer().TemplateResponse(
|
||||||
|
"hivemind/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
|
@ -17,14 +17,13 @@ livestream_static_files = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
livestream_ext: APIRouter = APIRouter(
|
livestream_ext: APIRouter = APIRouter(prefix="/livestream", tags=["livestream"])
|
||||||
prefix="/livestream",
|
|
||||||
tags=["livestream"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def livestream_renderer():
|
def livestream_renderer():
|
||||||
return template_renderer(["lnbits/extensions/livestream/templates"])
|
return template_renderer(["lnbits/extensions/livestream/templates"])
|
||||||
|
|
||||||
|
|
||||||
from .lnurl import * # noqa
|
from .lnurl import * # noqa
|
||||||
from .tasks import wait_for_paid_invoices
|
from .tasks import wait_for_paid_invoices
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
|
|
|
@ -67,8 +67,7 @@ async def update_current_track(ls_id: int, track_id: Optional[int]):
|
||||||
|
|
||||||
async def update_livestream_fee(ls_id: int, fee_pct: int):
|
async def update_livestream_fee(ls_id: int, fee_pct: int):
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"UPDATE livestream.livestreams SET fee_pct = ? WHERE id = ?",
|
"UPDATE livestream.livestreams SET fee_pct = ? WHERE id = ?", (fee_pct, ls_id)
|
||||||
(fee_pct, ls_id),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,17 @@ async def lnurl_livestream(ls_id, request: Request):
|
||||||
ls = await get_livestream(ls_id)
|
ls = await get_livestream(ls_id)
|
||||||
if not ls:
|
if not ls:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Livestream not found."
|
||||||
detail="Livestream not found."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
track = await get_track(ls.current_track)
|
track = await get_track(ls.current_track)
|
||||||
if not track:
|
if not track:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="This livestream is offline."
|
||||||
detail="This livestream is offline."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
resp = LnurlPayResponse(
|
resp = LnurlPayResponse(
|
||||||
callback=request.url_for(
|
callback=request.url_for("livestream.lnurl_callback", track_id=track.id),
|
||||||
"livestream.lnurl_callback", track_id=track.id
|
|
||||||
),
|
|
||||||
min_sendable=track.min_sendable,
|
min_sendable=track.min_sendable,
|
||||||
max_sendable=track.max_sendable,
|
max_sendable=track.max_sendable,
|
||||||
metadata=await track.lnurlpay_metadata(),
|
metadata=await track.lnurlpay_metadata(),
|
||||||
|
@ -49,15 +45,10 @@ async def lnurl_livestream(ls_id, request: Request):
|
||||||
async def lnurl_track(track_id, request: Request):
|
async def lnurl_track(track_id, request: Request):
|
||||||
track = await get_track(track_id)
|
track = await get_track(track_id)
|
||||||
if not track:
|
if not track:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Track not found.")
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
|
||||||
detail="Track not found."
|
|
||||||
)
|
|
||||||
|
|
||||||
resp = LnurlPayResponse(
|
resp = LnurlPayResponse(
|
||||||
callback=request.url_for(
|
callback=request.url_for("livestream.lnurl_callback", track_id=track.id),
|
||||||
"livestream.lnurl_callback", track_id=track.id
|
|
||||||
),
|
|
||||||
min_sendable=track.min_sendable,
|
min_sendable=track.min_sendable,
|
||||||
max_sendable=track.max_sendable,
|
max_sendable=track.max_sendable,
|
||||||
metadata=await track.lnurlpay_metadata(),
|
metadata=await track.lnurlpay_metadata(),
|
||||||
|
@ -70,29 +61,28 @@ async def lnurl_track(track_id, request: Request):
|
||||||
|
|
||||||
|
|
||||||
@livestream_ext.get("/lnurl/cb/{track_id}", name="livestream.lnurl_callback")
|
@livestream_ext.get("/lnurl/cb/{track_id}", name="livestream.lnurl_callback")
|
||||||
async def lnurl_callback(track_id, request: Request, amount: int = Query(...), comment: str = Query("")):
|
async def lnurl_callback(
|
||||||
|
track_id, request: Request, amount: int = Query(...), comment: str = Query("")
|
||||||
|
):
|
||||||
track = await get_track(track_id)
|
track = await get_track(track_id)
|
||||||
if not track:
|
if not track:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Track not found.")
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
|
||||||
detail="Track not found."
|
|
||||||
)
|
|
||||||
|
|
||||||
amount_received = int(amount or 0)
|
amount_received = int(amount or 0)
|
||||||
|
|
||||||
if amount_received < track.min_sendable:
|
if amount_received < track.min_sendable:
|
||||||
return LnurlErrorResponse(
|
return LnurlErrorResponse(
|
||||||
reason=f"Amount {round(amount_received / 1000)} is smaller than minimum {math.floor(track.min_sendable)}."
|
reason=f"Amount {round(amount_received / 1000)} is smaller than minimum {math.floor(track.min_sendable)}."
|
||||||
).dict()
|
).dict()
|
||||||
elif track.max_sendable < amount_received:
|
elif track.max_sendable < amount_received:
|
||||||
return LnurlErrorResponse(
|
return LnurlErrorResponse(
|
||||||
reason=f"Amount {round(amount_received / 1000)} is greater than maximum {math.floor(track.max_sendable)}."
|
reason=f"Amount {round(amount_received / 1000)} is greater than maximum {math.floor(track.max_sendable)}."
|
||||||
).dict()
|
).dict()
|
||||||
|
|
||||||
if len(comment or "") > 300:
|
if len(comment or "") > 300:
|
||||||
return LnurlErrorResponse(
|
return LnurlErrorResponse(
|
||||||
reason=f"Got a comment with {len(comment)} characters, but can only accept 300"
|
reason=f"Got a comment with {len(comment)} characters, but can only accept 300"
|
||||||
).dict()
|
).dict()
|
||||||
|
|
||||||
ls = await get_livestream_by_track(track_id)
|
ls = await get_livestream_by_track(track_id)
|
||||||
|
|
||||||
|
@ -112,9 +102,7 @@ async def lnurl_callback(track_id, request: Request, amount: int = Query(...), c
|
||||||
success_action = track.success_action(payment_hash, request=request)
|
success_action = track.success_action(payment_hash, request=request)
|
||||||
|
|
||||||
resp = LnurlPayActionResponse(
|
resp = LnurlPayActionResponse(
|
||||||
pr=payment_request,
|
pr=payment_request, success_action=success_action, routes=[]
|
||||||
success_action=success_action,
|
|
||||||
routes=[],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return resp.dict()
|
return resp.dict()
|
||||||
|
|
|
@ -17,6 +17,7 @@ class CreateTrack(BaseModel):
|
||||||
producer_id: str = Query(None)
|
producer_id: str = Query(None)
|
||||||
producer_name: str = Query(None)
|
producer_name: str = Query(None)
|
||||||
|
|
||||||
|
|
||||||
class Livestream(BaseModel):
|
class Livestream(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
wallet: str
|
wallet: str
|
||||||
|
@ -68,15 +69,15 @@ class Track(BaseModel):
|
||||||
|
|
||||||
return LnurlPayMetadata(json.dumps([["text/plain", description]]))
|
return LnurlPayMetadata(json.dumps([["text/plain", description]]))
|
||||||
|
|
||||||
def success_action(self, payment_hash: str, request: Request) -> Optional[LnurlPaySuccessAction]:
|
def success_action(
|
||||||
|
self, payment_hash: str, request: Request
|
||||||
|
) -> Optional[LnurlPaySuccessAction]:
|
||||||
if not self.download_url:
|
if not self.download_url:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return UrlAction(
|
return UrlAction(
|
||||||
url=request.url_for(
|
url=request.url_for(
|
||||||
"livestream.track_redirect_download",
|
"livestream.track_redirect_download", track_id=self.id, p=payment_hash
|
||||||
track_id=self.id,
|
|
||||||
p=payment_hash
|
|
||||||
),
|
),
|
||||||
description=f"Download the track {self.name}!",
|
description=f"Download the track {self.name}!",
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,6 +18,7 @@ async def wait_for_paid_invoices():
|
||||||
payment = await invoice_queue.get()
|
payment = await invoice_queue.get()
|
||||||
await on_invoice_paid(payment)
|
await on_invoice_paid(payment)
|
||||||
|
|
||||||
|
|
||||||
# async def register_listeners():
|
# async def register_listeners():
|
||||||
# invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
# invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
||||||
# register_invoice_listener(invoice_paid_chan_send)
|
# register_invoice_listener(invoice_paid_chan_send)
|
||||||
|
|
|
@ -17,7 +17,9 @@ from .crud import get_livestream_by_track, get_track
|
||||||
|
|
||||||
@livestream_ext.get("/", response_class=HTMLResponse)
|
@livestream_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 livestream_renderer().TemplateResponse("livestream/index.html", {"request": request, "user": user.dict()})
|
return livestream_renderer().TemplateResponse(
|
||||||
|
"livestream/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@livestream_ext.get("/track/{track_id}", name="livestream.track_redirect_download")
|
@livestream_ext.get("/track/{track_id}", name="livestream.track_redirect_download")
|
||||||
|
@ -31,12 +33,12 @@ async def track_redirect_download(track_id, p: str = Query(...)):
|
||||||
if not payment:
|
if not payment:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND,
|
||||||
detail=f"Couldn't find the payment {payment_hash} or track {track.id}."
|
detail=f"Couldn't find the payment {payment_hash} or track {track.id}.",
|
||||||
)
|
)
|
||||||
|
|
||||||
if payment.pending:
|
if payment.pending:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.PAYMENT_REQUIRED,
|
status_code=HTTPStatus.PAYMENT_REQUIRED,
|
||||||
detail=f"Payment {payment_hash} wasn't received yet. Please try again in a minute."
|
detail=f"Payment {payment_hash} wasn't received yet. Please try again in a minute.",
|
||||||
)
|
)
|
||||||
return RedirectResponse(url=track.download_url)
|
return RedirectResponse(url=track.download_url)
|
||||||
|
|
|
@ -23,27 +23,29 @@ from .crud import (
|
||||||
|
|
||||||
|
|
||||||
@livestream_ext.get("/api/v1/livestream")
|
@livestream_ext.get("/api/v1/livestream")
|
||||||
async def api_livestream_from_wallet(req: Request, g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_livestream_from_wallet(
|
||||||
|
req: Request, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
ls = await get_or_create_livestream_by_wallet(g.wallet.id)
|
ls = await get_or_create_livestream_by_wallet(g.wallet.id)
|
||||||
tracks = await get_tracks(ls.id)
|
tracks = await get_tracks(ls.id)
|
||||||
producers = await get_producers(ls.id)
|
producers = await get_producers(ls.id)
|
||||||
print("INIT", ls, tracks, producers)
|
print("INIT", ls, tracks, producers)
|
||||||
try:
|
try:
|
||||||
return {
|
return {
|
||||||
**ls.dict(),
|
**ls.dict(),
|
||||||
**{
|
**{
|
||||||
"lnurl": ls.lnurl(request=req),
|
"lnurl": ls.lnurl(request=req),
|
||||||
"tracks": [
|
"tracks": [
|
||||||
dict(lnurl=track.lnurl(request=req), **track.dict())
|
dict(lnurl=track.lnurl(request=req), **track.dict())
|
||||||
for track in tracks
|
for track in tracks
|
||||||
],
|
],
|
||||||
"producers": [producer.dict() for producer in producers],
|
"producers": [producer.dict() for producer in producers],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
except LnurlInvalidUrl:
|
except LnurlInvalidUrl:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.UPGRADE_REQUIRED,
|
status_code=HTTPStatus.UPGRADE_REQUIRED,
|
||||||
detail="LNURLs need to be delivered over a publically accessible `https` domain or Tor."
|
detail="LNURLs need to be delivered over a publically accessible `https` domain or Tor.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +72,9 @@ async def api_update_fee(fee_pct, g: WalletTypeInfo = Depends(get_key_type)):
|
||||||
|
|
||||||
@livestream_ext.post("/api/v1/livestream/tracks")
|
@livestream_ext.post("/api/v1/livestream/tracks")
|
||||||
@livestream_ext.put("/api/v1/livestream/tracks/{id}")
|
@livestream_ext.put("/api/v1/livestream/tracks/{id}")
|
||||||
async def api_add_track(data: CreateTrack, id=None, g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_add_track(
|
||||||
|
data: CreateTrack, id=None, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
ls = await get_or_create_livestream_by_wallet(g.wallet.id)
|
ls = await get_or_create_livestream_by_wallet(g.wallet.id)
|
||||||
|
|
||||||
if data.producer_id:
|
if data.producer_id:
|
||||||
|
@ -82,21 +86,10 @@ async def api_add_track(data: CreateTrack, id=None, g: WalletTypeInfo = Depends(
|
||||||
|
|
||||||
if id:
|
if id:
|
||||||
await update_track(
|
await update_track(
|
||||||
ls.id,
|
ls.id, id, data.name, data.download_url, data.price_msat or 0, p_id
|
||||||
id,
|
|
||||||
data.name,
|
|
||||||
data.download_url,
|
|
||||||
data.price_msat or 0,
|
|
||||||
p_id,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await add_track(
|
await add_track(ls.id, data.name, data.download_url, data.price_msat or 0, p_id)
|
||||||
ls.id,
|
|
||||||
data.name,
|
|
||||||
data.download_url,
|
|
||||||
data.price_msat or 0,
|
|
||||||
p_id,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ async def lndhub_payinvoice(
|
||||||
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Payment failed")
|
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Payment failed")
|
||||||
|
|
||||||
invoice: bolt11.Invoice = bolt11.decode(r_invoice.invoice)
|
invoice: bolt11.Invoice = bolt11.decode(r_invoice.invoice)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"payment_error": "",
|
"payment_error": "",
|
||||||
"payment_preimage": "0" * 64,
|
"payment_preimage": "0" * 64,
|
||||||
|
|
|
@ -8,9 +8,7 @@ from .models import lnurlposs, lnurlpospayment, createLnurlpos
|
||||||
###############lnurlposS##########################
|
###############lnurlposS##########################
|
||||||
|
|
||||||
|
|
||||||
async def create_lnurlpos(
|
async def create_lnurlpos(data: createLnurlpos,) -> lnurlposs:
|
||||||
data: createLnurlpos,
|
|
||||||
) -> lnurlposs:
|
|
||||||
print(data)
|
print(data)
|
||||||
lnurlpos_id = urlsafe_short_hash()
|
lnurlpos_id = urlsafe_short_hash()
|
||||||
lnurlpos_key = urlsafe_short_hash()
|
lnurlpos_key = urlsafe_short_hash()
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
import math
|
import math
|
||||||
from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore
|
from lnurl import (
|
||||||
|
LnurlPayResponse,
|
||||||
|
LnurlPayActionResponse,
|
||||||
|
LnurlErrorResponse,
|
||||||
|
) # type: ignore
|
||||||
from lnurl.types import LnurlPayMetadata
|
from lnurl.types import LnurlPayMetadata
|
||||||
from lnbits.core.services import create_invoice
|
from lnbits.core.services import create_invoice
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
|
|
@ -54,6 +54,5 @@ async def displaypin(request: Request, paymentid: str = Query(None)):
|
||||||
"lnurlpos/paid.html", {"request": request, "pin": lnurlpospayment.pin}
|
"lnurlpos/paid.html", {"request": request, "pin": lnurlpospayment.pin}
|
||||||
)
|
)
|
||||||
return lnurlpos_renderer().TemplateResponse(
|
return lnurlpos_renderer().TemplateResponse(
|
||||||
"lnurlpos/error.html",
|
"lnurlpos/error.html", {"request": request, "pin": "filler", "not_paid": True}
|
||||||
{"request": request, "pin": "filler", "not_paid": True},
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,10 +5,8 @@ from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_paywall")
|
db = Database("ext_paywall")
|
||||||
|
|
||||||
paywall_ext: APIRouter = APIRouter(
|
paywall_ext: APIRouter = APIRouter(prefix="/paywall", tags=["Paywall"])
|
||||||
prefix="/paywall",
|
|
||||||
tags=["Paywall"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def paywall_renderer():
|
def paywall_renderer():
|
||||||
return template_renderer(["lnbits/extensions/paywall/templates"])
|
return template_renderer(["lnbits/extensions/paywall/templates"])
|
||||||
|
|
|
@ -6,17 +6,22 @@ from . import db
|
||||||
from .models import CreatePaywall, Paywall
|
from .models import CreatePaywall, Paywall
|
||||||
|
|
||||||
|
|
||||||
async def create_paywall(
|
async def create_paywall(wallet_id: str, data: CreatePaywall) -> Paywall:
|
||||||
wallet_id: str,
|
|
||||||
data: CreatePaywall
|
|
||||||
) -> Paywall:
|
|
||||||
paywall_id = urlsafe_short_hash()
|
paywall_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO paywall.paywalls (id, wallet, url, memo, description, amount, remembers)
|
INSERT INTO paywall.paywalls (id, wallet, url, memo, description, amount, remembers)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(paywall_id, wallet_id, data.url, data.memo, data.description, data.amount, int(data.remembers)),
|
(
|
||||||
|
paywall_id,
|
||||||
|
wallet_id,
|
||||||
|
data.url,
|
||||||
|
data.memo,
|
||||||
|
data.description,
|
||||||
|
data.amount,
|
||||||
|
int(data.remembers),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
paywall = await get_paywall(paywall_id)
|
paywall = await get_paywall(paywall_id)
|
||||||
|
|
|
@ -13,12 +13,15 @@ class CreatePaywall(BaseModel):
|
||||||
amount: int = Query(..., ge=0)
|
amount: int = Query(..., ge=0)
|
||||||
remembers: bool = Query(...)
|
remembers: bool = Query(...)
|
||||||
|
|
||||||
|
|
||||||
class CreatePaywallInvoice(BaseModel):
|
class CreatePaywallInvoice(BaseModel):
|
||||||
amount: int = Query(..., ge=1)
|
amount: int = Query(..., ge=1)
|
||||||
|
|
||||||
|
|
||||||
class CheckPaywallInvoice(BaseModel):
|
class CheckPaywallInvoice(BaseModel):
|
||||||
payment_hash: str = Query(...)
|
payment_hash: str = Query(...)
|
||||||
|
|
||||||
|
|
||||||
class Paywall(BaseModel):
|
class Paywall(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
|
|
@ -13,7 +13,9 @@ from .crud import get_paywall
|
||||||
|
|
||||||
@paywall_ext.get("/")
|
@paywall_ext.get("/")
|
||||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
return paywall_renderer().TemplateResponse("paywall/index.html", {"request": request, "user": user.dict()})
|
return paywall_renderer().TemplateResponse(
|
||||||
|
"paywall/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@paywall_ext.get("/{paywall_id}")
|
@paywall_ext.get("/{paywall_id}")
|
||||||
|
@ -23,4 +25,6 @@ async def display(request: Request, paywall_id):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist."
|
status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist."
|
||||||
)
|
)
|
||||||
return paywall_renderer().TemplateResponse("paywall/display.html", {"request": request, "paywall": paywall})
|
return paywall_renderer().TemplateResponse(
|
||||||
|
"paywall/display.html", {"request": request, "paywall": paywall}
|
||||||
|
)
|
||||||
|
|
|
@ -13,7 +13,9 @@ from .models import CheckPaywallInvoice, CreatePaywall, CreatePaywallInvoice
|
||||||
|
|
||||||
|
|
||||||
@paywall_ext.get("/api/v1/paywalls")
|
@paywall_ext.get("/api/v1/paywalls")
|
||||||
async def api_paywalls(wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
|
async def api_paywalls(
|
||||||
|
wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
||||||
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
|
@ -23,47 +25,51 @@ async def api_paywalls(wallet: WalletTypeInfo = Depends(get_key_type), all_walle
|
||||||
|
|
||||||
|
|
||||||
@paywall_ext.post("/api/v1/paywalls")
|
@paywall_ext.post("/api/v1/paywalls")
|
||||||
async def api_paywall_create(data: CreatePaywall, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_paywall_create(
|
||||||
|
data: CreatePaywall, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
paywall = await create_paywall(wallet_id=wallet.wallet.id, data=data)
|
paywall = await create_paywall(wallet_id=wallet.wallet.id, data=data)
|
||||||
return paywall.dict()
|
return paywall.dict()
|
||||||
|
|
||||||
|
|
||||||
@paywall_ext.delete("/api/v1/paywalls/{paywall_id}")
|
@paywall_ext.delete("/api/v1/paywalls/{paywall_id}")
|
||||||
async def api_paywall_delete(paywall_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_paywall_delete(
|
||||||
|
paywall_id, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
paywall = await get_paywall(paywall_id)
|
paywall = await get_paywall(paywall_id)
|
||||||
|
|
||||||
if not paywall:
|
if not paywall:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist."
|
||||||
detail="Paywall does not exist."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if paywall.wallet != wallet.wallet.id:
|
if paywall.wallet != wallet.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your paywall."
|
||||||
detail="Not your paywall."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
await delete_paywall(paywall_id)
|
await delete_paywall(paywall_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|
||||||
|
|
||||||
@paywall_ext.post("/api/v1/paywalls/{paywall_id}/invoice")
|
@paywall_ext.post("/api/v1/paywalls/{paywall_id}/invoice")
|
||||||
async def api_paywall_create_invoice(paywall_id, data: CreatePaywallInvoice, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_paywall_create_invoice(
|
||||||
|
paywall_id,
|
||||||
|
data: CreatePaywallInvoice,
|
||||||
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
|
):
|
||||||
paywall = await get_paywall(paywall_id)
|
paywall = await get_paywall(paywall_id)
|
||||||
print("PAYW", paywall)
|
print("PAYW", paywall)
|
||||||
print("DATA", data)
|
print("DATA", data)
|
||||||
|
|
||||||
if data.amount < paywall.amount:
|
if data.amount < paywall.amount:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
detail=f"Minimum amount is {paywall.amount} sat."
|
detail=f"Minimum amount is {paywall.amount} sat.",
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
amount = (
|
amount = data.amount if data.amount > paywall.amount else paywall.amount
|
||||||
data.amount if data.amount > paywall.amount else paywall.amount
|
|
||||||
)
|
|
||||||
payment_hash, payment_request = await create_invoice(
|
payment_hash, payment_request = await create_invoice(
|
||||||
wallet_id=paywall.wallet,
|
wallet_id=paywall.wallet,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
|
@ -71,10 +77,7 @@ async def api_paywall_create_invoice(paywall_id, data: CreatePaywallInvoice, wal
|
||||||
extra={"tag": "paywall"},
|
extra={"tag": "paywall"},
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
||||||
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}
|
||||||
|
|
||||||
|
@ -85,9 +88,8 @@ async def api_paywal_check_invoice(data: CheckPaywallInvoice, paywall_id):
|
||||||
payment_hash = data.payment_hash
|
payment_hash = data.payment_hash
|
||||||
if not paywall:
|
if not paywall:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Paywall does not exist."
|
||||||
detail="Paywall does not exist."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
status = await check_invoice_status(paywall.wallet, payment_hash)
|
status = await check_invoice_status(paywall.wallet, payment_hash)
|
||||||
|
|
|
@ -15,10 +15,7 @@ from .models import (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def create_satsdice_pay(
|
async def create_satsdice_pay(wallet_id: str, data: CreateSatsDiceLink) -> satsdiceLink:
|
||||||
wallet_id: str,
|
|
||||||
data: CreateSatsDiceLink,
|
|
||||||
) -> satsdiceLink:
|
|
||||||
satsdice_id = urlsafe_short_hash()
|
satsdice_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -49,9 +49,7 @@ async def api_lnurlp_response(req: Request, link_id: str = Query(None)):
|
||||||
name="satsdice.api_lnurlp_callback",
|
name="satsdice.api_lnurlp_callback",
|
||||||
)
|
)
|
||||||
async def api_lnurlp_callback(
|
async def api_lnurlp_callback(
|
||||||
req: Request,
|
req: Request, link_id: str = Query(None), amount: str = Query(None)
|
||||||
link_id: str = Query(None),
|
|
||||||
amount: str = Query(None),
|
|
||||||
):
|
):
|
||||||
link = await get_satsdice_pay(link_id)
|
link = await get_satsdice_pay(link_id)
|
||||||
print(link)
|
print(link)
|
||||||
|
@ -95,11 +93,7 @@ async def api_lnurlp_callback(
|
||||||
}
|
}
|
||||||
|
|
||||||
await create_satsdice_payment(data)
|
await create_satsdice_payment(data)
|
||||||
payResponse = {
|
payResponse = {"pr": payment_request, "successAction": success_action, "routes": []}
|
||||||
"pr": payment_request,
|
|
||||||
"successAction": success_action,
|
|
||||||
"routes": [],
|
|
||||||
}
|
|
||||||
print(json.dumps(payResponse))
|
print(json.dumps(payResponse))
|
||||||
|
|
||||||
return json.dumps(payResponse)
|
return json.dumps(payResponse)
|
||||||
|
|
|
@ -94,12 +94,7 @@ async def displaywin(
|
||||||
if not rand < chance or not status["paid"]:
|
if not rand < chance or not status["paid"]:
|
||||||
return satsdice_renderer().TemplateResponse(
|
return satsdice_renderer().TemplateResponse(
|
||||||
"satsdice/error.html",
|
"satsdice/error.html",
|
||||||
{
|
{"request": request, "link": satsdicelink.id, "paid": False, "lost": True},
|
||||||
"request": request,
|
|
||||||
"link": satsdicelink.id,
|
|
||||||
"paid": False,
|
|
||||||
"lost": True,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
await update_satsdice_payment(payment_hash, paid=1)
|
await update_satsdice_payment(payment_hash, paid=1)
|
||||||
paylink = await get_satsdice_payment(payment_hash)
|
paylink = await get_satsdice_payment(payment_hash)
|
||||||
|
|
|
@ -92,7 +92,6 @@ async def api_link_create_or_update(
|
||||||
detail="Come on, seriously, this isn't your satsdice!",
|
detail="Come on, seriously, this isn't your satsdice!",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
data.wallet = wallet.wallet.id
|
data.wallet = wallet.wallet.id
|
||||||
link = await update_satsdice_pay(link_id, **data.dict())
|
link = await update_satsdice_pay(link_id, **data.dict())
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -10,6 +10,7 @@ class Target(BaseModel):
|
||||||
percent: int
|
percent: int
|
||||||
alias: Optional[str]
|
alias: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class TargetPutList(BaseModel):
|
class TargetPutList(BaseModel):
|
||||||
wallet: str = Query(...)
|
wallet: str = Query(...)
|
||||||
alias: str = Query("")
|
alias: str = Query("")
|
||||||
|
|
|
@ -38,8 +38,7 @@ async def api_targets_set(
|
||||||
|
|
||||||
if wallet.id == wal.wallet.id:
|
if wallet.id == wal.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="Can't split to itself."
|
||||||
detail="Can't split to itself.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if entry.percent < 0:
|
if entry.percent < 0:
|
||||||
|
@ -49,14 +48,18 @@ async def api_targets_set(
|
||||||
)
|
)
|
||||||
|
|
||||||
targets.append(
|
targets.append(
|
||||||
Target(wallet=wallet.id, source=wal.wallet.id, percent=entry.percent, alias=entry.alias)
|
Target(
|
||||||
|
wallet=wallet.id,
|
||||||
|
source=wal.wallet.id,
|
||||||
|
percent=entry.percent,
|
||||||
|
alias=entry.alias,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
percent_sum = sum([target.percent for target in targets])
|
percent_sum = sum([target.percent for target in targets])
|
||||||
if percent_sum > 100:
|
if percent_sum > 100:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="Splitting over 100%."
|
||||||
detail="Splitting over 100%.",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await set_targets(wal.wallet.id, targets)
|
await set_targets(wal.wallet.id, targets)
|
||||||
|
|
|
@ -5,13 +5,12 @@ from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_streamalerts")
|
db = Database("ext_streamalerts")
|
||||||
|
|
||||||
streamalerts_ext: APIRouter = APIRouter(
|
streamalerts_ext: APIRouter = APIRouter(prefix="/streamalerts", tags=["streamalerts"])
|
||||||
prefix="/streamalerts",
|
|
||||||
tags=["streamalerts"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def streamalerts_renderer():
|
def streamalerts_renderer():
|
||||||
return template_renderer(["lnbits/extensions/streamalerts/templates"])
|
return template_renderer(["lnbits/extensions/streamalerts/templates"])
|
||||||
|
|
||||||
|
|
||||||
from .views import * # noqa
|
from .views import * # noqa
|
||||||
from .views_api import * # noqa
|
from .views_api import * # noqa
|
||||||
|
|
|
@ -25,9 +25,7 @@ async def get_charge_details(service_id):
|
||||||
|
|
||||||
These might be different depending for services implemented in the future.
|
These might be different depending for services implemented in the future.
|
||||||
"""
|
"""
|
||||||
details = {
|
details = {"time": 1440}
|
||||||
"time": 1440,
|
|
||||||
}
|
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
wallet_id = service.wallet
|
wallet_id = service.wallet
|
||||||
wallet = await get_wallet(wallet_id)
|
wallet = await get_wallet(wallet_id)
|
||||||
|
@ -111,9 +109,7 @@ async def post_donation(donation_id: str) -> tuple:
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
async def create_service(
|
async def create_service(data: CreateService) -> Service:
|
||||||
data: CreateService
|
|
||||||
) -> Service:
|
|
||||||
"""Create a new Service"""
|
"""Create a new Service"""
|
||||||
|
|
||||||
returning = "" if db.type == SQLITE else "RETURNING ID"
|
returning = "" if db.type == SQLITE else "RETURNING ID"
|
||||||
|
@ -215,10 +211,7 @@ async def service_add_token(service_id, token):
|
||||||
return False
|
return False
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"UPDATE streamalerts.Services SET authenticated = 1, token = ? where id = ?",
|
"UPDATE streamalerts.Services SET authenticated = 1, token = ? where id = ?",
|
||||||
(
|
(token, service_id),
|
||||||
token,
|
|
||||||
service_id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,14 @@ class CreateService(BaseModel):
|
||||||
servicename: str = Query(...)
|
servicename: str = Query(...)
|
||||||
onchain: str = Query(None)
|
onchain: str = Query(None)
|
||||||
|
|
||||||
|
|
||||||
class CreateDonation(BaseModel):
|
class CreateDonation(BaseModel):
|
||||||
name: str = Query("Anonymous")
|
name: str = Query("Anonymous")
|
||||||
sats: int = Query(..., ge=1)
|
sats: int = Query(..., ge=1)
|
||||||
service: int = Query(...)
|
service: int = Query(...)
|
||||||
message: str = Query("")
|
message: str = Query("")
|
||||||
|
|
||||||
|
|
||||||
class ValidateDonation(BaseModel):
|
class ValidateDonation(BaseModel):
|
||||||
id: str = Query(...)
|
id: str = Query(...)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ templates = Jinja2Templates(directory="templates")
|
||||||
@streamalerts_ext.get("/", response_class=HTMLResponse)
|
@streamalerts_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 the extension's settings page"""
|
"""Return the extension's settings page"""
|
||||||
return streamalerts_renderer().TemplateResponse("streamalerts/index.html", {"request": request, "user": user.dict()})
|
return streamalerts_renderer().TemplateResponse(
|
||||||
|
"streamalerts/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@streamalerts_ext.get("/{state}")
|
@streamalerts_ext.get("/{state}")
|
||||||
|
@ -31,9 +33,5 @@ async def donation(state, request: Request):
|
||||||
)
|
)
|
||||||
return streamalerts_renderer().TemplateResponse(
|
return streamalerts_renderer().TemplateResponse(
|
||||||
"streamalerts/display.html",
|
"streamalerts/display.html",
|
||||||
{
|
{"request": request, "twitchuser": service.twitchuser, "service": service.id},
|
||||||
"request": request,
|
|
||||||
"twitchuser": service.twitchuser,
|
|
||||||
"service":service.id
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,14 +35,14 @@ from .crud import (
|
||||||
|
|
||||||
|
|
||||||
@streamalerts_ext.post("/api/v1/services")
|
@streamalerts_ext.post("/api/v1/services")
|
||||||
async def api_create_service(data : CreateService, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_create_service(
|
||||||
|
data: CreateService, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
"""Create a service, which holds data about how/where to post donations"""
|
"""Create a service, which holds data about how/where to post donations"""
|
||||||
try:
|
try:
|
||||||
service = await create_service(data=data)
|
service = await create_service(data=data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
||||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
return service.dict()
|
return service.dict()
|
||||||
|
|
||||||
|
@ -68,23 +68,24 @@ async def api_get_access(service_id, request: Request):
|
||||||
return RedirectResponse(redirect_url)
|
return RedirectResponse(redirect_url)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="Service does not exist!"
|
||||||
detail="Service does not exist!"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@streamalerts_ext.get("/api/v1/authenticate/{service_id}")
|
@streamalerts_ext.get("/api/v1/authenticate/{service_id}")
|
||||||
async def api_authenticate_service(service_id, request: Request, code: str = Query(...), state: str = Query(...)):
|
async def api_authenticate_service(
|
||||||
|
service_id, request: Request, code: str = Query(...), state: str = Query(...)
|
||||||
|
):
|
||||||
"""Endpoint visited via redirect during third party API authentication
|
"""Endpoint visited via redirect during third party API authentication
|
||||||
|
|
||||||
If successful, an API access token will be added to the service, and
|
If successful, an API access token will be added to the service, and
|
||||||
the user will be redirected to index.html.
|
the user will be redirected to index.html.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
if service.state != state:
|
if service.state != state:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="State doesn't match!"
|
||||||
detail="State doesn't match!"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
redirect_uri = request.url.scheme + "://" + request.headers["Host"]
|
redirect_uri = request.url.scheme + "://" + request.headers["Host"]
|
||||||
|
@ -94,8 +95,7 @@ async def api_authenticate_service(service_id, request: Request, code: str = Que
|
||||||
return RedirectResponse(url)
|
return RedirectResponse(url)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="Service already authenticated!"
|
||||||
detail="Service already authenticated!"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ async def api_create_donation(data: CreateDonation, request: Request):
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
charge_details = await get_charge_details(service.id)
|
charge_details = await get_charge_details(service.id)
|
||||||
name = data.name
|
name = data.name
|
||||||
|
|
||||||
description = f"{sats} sats donation from {name} to {service.twitchuser}"
|
description = f"{sats} sats donation from {name} to {service.twitchuser}"
|
||||||
charge = await create_charge(
|
charge = await create_charge(
|
||||||
amount=sats,
|
amount=sats,
|
||||||
|
@ -132,7 +132,7 @@ async def api_create_donation(data: CreateDonation, request: Request):
|
||||||
cur_code=cur_code,
|
cur_code=cur_code,
|
||||||
sats=data.sats,
|
sats=data.sats,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
service=data.service
|
service=data.service,
|
||||||
)
|
)
|
||||||
return {"redirect_url": f"/satspay/{charge.id}"}
|
return {"redirect_url": f"/satspay/{charge.id}"}
|
||||||
|
|
||||||
|
@ -141,15 +141,14 @@ async def api_create_donation(data: CreateDonation, request: Request):
|
||||||
async def api_post_donation(request: Request, data: ValidateDonation):
|
async def api_post_donation(request: Request, data: ValidateDonation):
|
||||||
"""Post a paid donation to Stremalabs/StreamElements.
|
"""Post a paid donation to Stremalabs/StreamElements.
|
||||||
This endpoint acts as a webhook for the SatsPayServer extension."""
|
This endpoint acts as a webhook for the SatsPayServer extension."""
|
||||||
|
|
||||||
donation_id = data.id
|
donation_id = data.id
|
||||||
charge = await get_charge(donation_id)
|
charge = await get_charge(donation_id)
|
||||||
if charge and charge.paid:
|
if charge and charge.paid:
|
||||||
return await post_donation(donation_id)
|
return await post_donation(donation_id)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="Not a paid charge!"
|
||||||
detail="Not a paid charge!"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,58 +177,55 @@ async def api_get_donations(g: WalletTypeInfo = Depends(get_key_type)):
|
||||||
|
|
||||||
|
|
||||||
@streamalerts_ext.put("/api/v1/donations/{donation_id}")
|
@streamalerts_ext.put("/api/v1/donations/{donation_id}")
|
||||||
async def api_update_donation(data: CreateDonation, donation_id=None, g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_update_donation(
|
||||||
|
data: CreateDonation, donation_id=None, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
"""Update a donation with the data given in the request"""
|
"""Update a donation with the data given in the request"""
|
||||||
if donation_id:
|
if donation_id:
|
||||||
donation = await get_donation(donation_id)
|
donation = await get_donation(donation_id)
|
||||||
|
|
||||||
if not donation:
|
if not donation:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Donation does not exist."
|
||||||
detail="Donation does not exist."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if donation.wallet != g.wallet.id:
|
if donation.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your donation."
|
||||||
detail="Not your donation."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
donation = await update_donation(donation_id, **data.dict())
|
donation = await update_donation(donation_id, **data.dict())
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="No donation ID specified"
|
||||||
detail="No donation ID specified"
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return donation.dict()
|
return donation.dict()
|
||||||
|
|
||||||
|
|
||||||
@streamalerts_ext.put("/api/v1/services/{service_id}")
|
@streamalerts_ext.put("/api/v1/services/{service_id}")
|
||||||
async def api_update_service(data: CreateService, service_id=None, g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_update_service(
|
||||||
|
data: CreateService, service_id=None, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
"""Update a service with the data given in the request"""
|
"""Update a service with the data given in the request"""
|
||||||
if service_id:
|
if service_id:
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
|
|
||||||
if not service:
|
if not service:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Service does not exist."
|
||||||
detail="Service does not exist."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if service.wallet != g.wallet.id:
|
if service.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your service."
|
||||||
detail="Not your service."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
service = await update_service(service_id, **data.dict())
|
service = await update_service(service_id, **data.dict())
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST, detail="No service ID specified"
|
||||||
detail="No service ID specified"
|
)
|
||||||
)
|
|
||||||
return service.dict()
|
return service.dict()
|
||||||
|
|
||||||
|
|
||||||
|
@ -239,14 +235,13 @@ async def api_delete_donation(donation_id, g: WalletTypeInfo = Depends(get_key_t
|
||||||
donation = await get_donation(donation_id)
|
donation = await get_donation(donation_id)
|
||||||
if not donation:
|
if not donation:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="No donation with this ID!"
|
||||||
detail="No donation with this ID!"
|
)
|
||||||
)
|
|
||||||
if donation.wallet != g.wallet.id:
|
if donation.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN,
|
||||||
detail="Not authorized to delete this donation!"
|
detail="Not authorized to delete this donation!",
|
||||||
)
|
)
|
||||||
await delete_donation(donation_id)
|
await delete_donation(donation_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|
||||||
|
@ -257,13 +252,12 @@ async def api_delete_service(service_id, g: WalletTypeInfo = Depends(get_key_typ
|
||||||
service = await get_service(service_id)
|
service = await get_service(service_id)
|
||||||
if not service:
|
if not service:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="No service with this ID!"
|
||||||
detail="No service with this ID!"
|
)
|
||||||
)
|
|
||||||
if service.wallet != g.wallet.id:
|
if service.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN,
|
||||||
detail="Not authorized to delete this service!"
|
detail="Not authorized to delete this service!",
|
||||||
)
|
)
|
||||||
await delete_service(service_id)
|
await delete_service(service_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|
|
@ -8,10 +8,8 @@ from lnbits.tasks import catch_everything_and_restart
|
||||||
|
|
||||||
db = Database("ext_subdomains")
|
db = Database("ext_subdomains")
|
||||||
|
|
||||||
subdomains_ext: APIRouter = APIRouter(
|
subdomains_ext: APIRouter = APIRouter(prefix="/subdomains", tags=["subdomains"])
|
||||||
prefix="/subdomains",
|
|
||||||
tags=["subdomains"]
|
|
||||||
)
|
|
||||||
|
|
||||||
def subdomains_renderer():
|
def subdomains_renderer():
|
||||||
return template_renderer(["lnbits/extensions/subdomains/templates"])
|
return template_renderer(["lnbits/extensions/subdomains/templates"])
|
||||||
|
@ -25,4 +23,3 @@ from .views_api import * # noqa
|
||||||
def subdomains_start():
|
def subdomains_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))
|
||||||
|
|
||||||
|
|
|
@ -50,11 +50,7 @@ async def cloudflare_deletesubdomain(domain: Domains, domain_id: str):
|
||||||
}
|
}
|
||||||
async with httpx.AsyncClient() as client:
|
async with httpx.AsyncClient() as client:
|
||||||
try:
|
try:
|
||||||
r = await client.delete(
|
r = await client.delete(url + "/" + domain_id, headers=header, timeout=40)
|
||||||
url + "/" + domain_id,
|
|
||||||
headers=header,
|
|
||||||
timeout=40,
|
|
||||||
)
|
|
||||||
cf_response = r.text
|
cf_response = r.text
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
cf_response = "Error occured"
|
cf_response = "Error occured"
|
||||||
|
|
|
@ -6,11 +6,7 @@ from . import db
|
||||||
from .models import CreateDomain, Domains, Subdomains
|
from .models import CreateDomain, Domains, Subdomains
|
||||||
|
|
||||||
|
|
||||||
async def create_subdomain(
|
async def create_subdomain(payment_hash, wallet, data: CreateDomain) -> Subdomains:
|
||||||
payment_hash,
|
|
||||||
wallet,
|
|
||||||
data: CreateDomain
|
|
||||||
) -> Subdomains:
|
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO subdomains.subdomain (id, domain, email, subdomain, ip, wallet, sats, duration, paid, record_type)
|
INSERT INTO subdomains.subdomain (id, domain, email, subdomain, ip, wallet, sats, duration, paid, record_type)
|
||||||
|
@ -105,9 +101,7 @@ async def delete_subdomain(subdomain_id: str) -> None:
|
||||||
# Domains
|
# Domains
|
||||||
|
|
||||||
|
|
||||||
async def create_domain(
|
async def create_domain(data: CreateDomain) -> Domains:
|
||||||
data: CreateDomain
|
|
||||||
) -> Domains:
|
|
||||||
domain_id = urlsafe_short_hash()
|
domain_id = urlsafe_short_hash()
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -12,6 +12,7 @@ class CreateDomain(BaseModel):
|
||||||
cost: int = Query(..., ge=0)
|
cost: int = Query(..., ge=0)
|
||||||
allowed_record_types: str = Query(...)
|
allowed_record_types: str = Query(...)
|
||||||
|
|
||||||
|
|
||||||
class CreateSubdomain(BaseModel):
|
class CreateSubdomain(BaseModel):
|
||||||
domain: str = Query(...)
|
domain: str = Query(...)
|
||||||
subdomain: str = Query(...)
|
subdomain: str = Query(...)
|
||||||
|
@ -21,6 +22,7 @@ class CreateSubdomain(BaseModel):
|
||||||
duration: int = Query(...)
|
duration: int = Query(...)
|
||||||
record_type: str = Query(...)
|
record_type: str = Query(...)
|
||||||
|
|
||||||
|
|
||||||
class Domains(BaseModel):
|
class Domains(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
@ -34,6 +36,7 @@ class Domains(BaseModel):
|
||||||
time: int
|
time: int
|
||||||
allowed_record_types: str
|
allowed_record_types: str
|
||||||
|
|
||||||
|
|
||||||
class Subdomains(BaseModel):
|
class Subdomains(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
|
|
@ -17,6 +17,7 @@ async def wait_for_paid_invoices():
|
||||||
payment = await invoice_queue.get()
|
payment = await invoice_queue.get()
|
||||||
await on_invoice_paid(payment)
|
await on_invoice_paid(payment)
|
||||||
|
|
||||||
|
|
||||||
# async def register_listeners():
|
# async def register_listeners():
|
||||||
# invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
# invoice_paid_chan_send, invoice_paid_chan_recv = trio.open_memory_channel(2)
|
||||||
# register_invoice_listener(invoice_paid_chan_send)
|
# register_invoice_listener(invoice_paid_chan_send)
|
||||||
|
|
|
@ -14,9 +14,12 @@ from .crud import get_domain
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
|
|
||||||
|
|
||||||
@subdomains_ext.get("/", response_class=HTMLResponse)
|
@subdomains_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 subdomains_renderer().TemplateResponse("subdomains/index.html", {"request": request, "user": user.dict()})
|
return subdomains_renderer().TemplateResponse(
|
||||||
|
"subdomains/index.html", {"request": request, "user": user.dict()}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@subdomains_ext.get("/{domain_id}")
|
@subdomains_ext.get("/{domain_id}")
|
||||||
|
@ -24,20 +27,20 @@ async def display(request: Request, domain_id):
|
||||||
domain = await get_domain(domain_id)
|
domain = await get_domain(domain_id)
|
||||||
if not domain:
|
if not domain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Domain does not exist."
|
||||||
detail="Domain does not exist."
|
|
||||||
)
|
)
|
||||||
allowed_records = (
|
allowed_records = (
|
||||||
domain.allowed_record_types.replace('"', "").replace(" ", "").split(",")
|
domain.allowed_record_types.replace('"', "").replace(" ", "").split(",")
|
||||||
)
|
)
|
||||||
|
|
||||||
return subdomains_renderer().TemplateResponse(
|
return subdomains_renderer().TemplateResponse(
|
||||||
"subdomains/display.html",{
|
"subdomains/display.html",
|
||||||
|
{
|
||||||
"request": request,
|
"request": request,
|
||||||
"domain_id": domain.id,
|
"domain_id": domain.id,
|
||||||
"domain_domain": domain.domain,
|
"domain_domain": domain.domain,
|
||||||
"domain_desc": domain.description,
|
"domain_desc": domain.description,
|
||||||
"domain_cost": domain.cost,
|
"domain_cost": domain.cost,
|
||||||
"domain_allowed_record_types": allowed_records,
|
"domain_allowed_record_types": allowed_records,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,9 @@ from .crud import (
|
||||||
|
|
||||||
|
|
||||||
@subdomains_ext.get("/api/v1/domains")
|
@subdomains_ext.get("/api/v1/domains")
|
||||||
async def api_domains(g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)):
|
async def api_domains(
|
||||||
|
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
||||||
|
):
|
||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
|
@ -39,19 +41,19 @@ async def api_domains(g: WalletTypeInfo = Depends(get_key_type), all_wallets: bo
|
||||||
|
|
||||||
@subdomains_ext.post("/api/v1/domains")
|
@subdomains_ext.post("/api/v1/domains")
|
||||||
@subdomains_ext.put("/api/v1/domains/{domain_id}")
|
@subdomains_ext.put("/api/v1/domains/{domain_id}")
|
||||||
async def api_domain_create(data: CreateDomain, domain_id=None, g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_domain_create(
|
||||||
|
data: CreateDomain, domain_id=None, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
if domain_id:
|
if domain_id:
|
||||||
domain = await get_domain(domain_id)
|
domain = await get_domain(domain_id)
|
||||||
|
|
||||||
if not domain:
|
if not domain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Domain does not exist."
|
||||||
detail="Domain does not exist."
|
|
||||||
)
|
)
|
||||||
if domain.wallet != g.wallet.id:
|
if domain.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your domain."
|
||||||
detail="Not your domain."
|
|
||||||
)
|
)
|
||||||
|
|
||||||
domain = await update_domain(domain_id, **data.dict())
|
domain = await update_domain(domain_id, **data.dict())
|
||||||
|
@ -66,14 +68,10 @@ async def api_domain_delete(domain_id, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
|
||||||
if not domain:
|
if not domain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="Domain does not exist."
|
||||||
detail="Domain does not exist."
|
)
|
||||||
)
|
|
||||||
if domain.wallet != g.wallet.id:
|
if domain.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your domain.")
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
|
||||||
detail="Not your domain."
|
|
||||||
)
|
|
||||||
|
|
||||||
await delete_domain(domain_id)
|
await delete_domain(domain_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
@ -83,7 +81,9 @@ async def api_domain_delete(domain_id, g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
|
||||||
|
|
||||||
@subdomains_ext.get("/api/v1/subdomains")
|
@subdomains_ext.get("/api/v1/subdomains")
|
||||||
async def api_subdomains(all_wallets: bool = Query(False), g: WalletTypeInfo = Depends(get_key_type)):
|
async def api_subdomains(
|
||||||
|
all_wallets: bool = Query(False), g: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
|
@ -99,22 +99,21 @@ async def api_subdomain_make_subdomain(domain_id, data: CreateSubdomain):
|
||||||
# If the request is coming for the non-existant domain
|
# If the request is coming for the non-existant domain
|
||||||
if not domain:
|
if not domain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="LNsubdomain does not exist."
|
||||||
detail="LNsubdomain does not exist."
|
)
|
||||||
)
|
|
||||||
## If record_type is not one of the allowed ones reject the request
|
## If record_type is not one of the allowed ones reject the request
|
||||||
if data.record_type not in domain.allowed_record_types:
|
if data.record_type not in domain.allowed_record_types:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
detail=f"{data.record_type} not a valid record."
|
detail=f"{data.record_type} not a valid record.",
|
||||||
)
|
)
|
||||||
|
|
||||||
## If domain already exist in our database reject it
|
## If domain already exist in our database reject it
|
||||||
if await get_subdomainBySubdomain(data.subdomain) is not None:
|
if await get_subdomainBySubdomain(data.subdomain) is not None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
detail=f"{data.subdomain}.{domain.domain} domain already taken."
|
detail=f"{data.subdomain}.{domain.domain} domain already taken.",
|
||||||
)
|
)
|
||||||
|
|
||||||
## Dry run cloudflare... (create and if create is sucessful delete it)
|
## Dry run cloudflare... (create and if create is sucessful delete it)
|
||||||
cf_response = await cloudflare_create_subdomain(
|
cf_response = await cloudflare_create_subdomain(
|
||||||
|
@ -124,12 +123,14 @@ async def api_subdomain_make_subdomain(domain_id, data: CreateSubdomain):
|
||||||
ip=data.ip,
|
ip=data.ip,
|
||||||
)
|
)
|
||||||
if cf_response["success"] == True:
|
if cf_response["success"] == True:
|
||||||
await cloudflare_deletesubdomain(domain=domain, domain_id=cf_response["result"]["id"])
|
await cloudflare_deletesubdomain(
|
||||||
|
domain=domain, domain_id=cf_response["result"]["id"]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
detail=f'Problem with cloudflare: {cf_response["errors"][0]["message"]}'
|
detail=f'Problem with cloudflare: {cf_response["errors"][0]["message"]}',
|
||||||
)
|
)
|
||||||
|
|
||||||
## ALL OK - create an invoice and return it to the user
|
## ALL OK - create an invoice and return it to the user
|
||||||
sats = data.sats
|
sats = data.sats
|
||||||
|
@ -142,10 +143,7 @@ async def api_subdomain_make_subdomain(domain_id, data: CreateSubdomain):
|
||||||
extra={"tag": "lnsubdomain"},
|
extra={"tag": "lnsubdomain"},
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e))
|
||||||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
||||||
detail=str(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
subdomain = await create_subdomain(
|
subdomain = await create_subdomain(
|
||||||
payment_hash=payment_hash, wallet=domain.wallet, data=data
|
payment_hash=payment_hash, wallet=domain.wallet, data=data
|
||||||
|
@ -153,9 +151,8 @@ async def api_subdomain_make_subdomain(domain_id, data: CreateSubdomain):
|
||||||
|
|
||||||
if not subdomain:
|
if not subdomain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="LNsubdomain could not be fetched."
|
||||||
detail="LNsubdomain could not be fetched."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
return {"payment_hash": payment_hash, "payment_request": payment_request}
|
return {"payment_hash": payment_hash, "payment_request": payment_request}
|
||||||
|
|
||||||
|
@ -181,15 +178,13 @@ async def api_subdomain_delete(subdomain_id, g: WalletTypeInfo = Depends(get_key
|
||||||
|
|
||||||
if not subdomain:
|
if not subdomain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="LNsubdomain does not exist."
|
||||||
detail="LNsubdomain does not exist."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
if subdomain.wallet != g.wallet.id:
|
if subdomain.wallet != g.wallet.id:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.FORBIDDEN,
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your subdomain."
|
||||||
detail="Not your subdomain."
|
)
|
||||||
)
|
|
||||||
|
|
||||||
await delete_subdomain(subdomain_id)
|
await delete_subdomain(subdomain_id)
|
||||||
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
raise HTTPException(status_code=HTTPStatus.NO_CONTENT)
|
||||||
|
|
|
@ -9,12 +9,7 @@ from lnbits.db import SQLITE
|
||||||
|
|
||||||
|
|
||||||
async def create_tip(
|
async def create_tip(
|
||||||
id: int,
|
id: int, wallet: str, message: str, name: str, sats: int, tipjar: str
|
||||||
wallet: str,
|
|
||||||
message: str,
|
|
||||||
name: str,
|
|
||||||
sats: int,
|
|
||||||
tipjar: str,
|
|
||||||
) -> Tip:
|
) -> Tip:
|
||||||
"""Create a new Tip"""
|
"""Create a new Tip"""
|
||||||
await db.execute(
|
await db.execute(
|
||||||
|
@ -110,8 +105,7 @@ async def update_tip(tip_id: str, **kwargs) -> Tip:
|
||||||
"""Update a Tip"""
|
"""Update a Tip"""
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||||
await db.execute(
|
await db.execute(
|
||||||
f"UPDATE tipjar.Tips SET {q} WHERE id = ?",
|
f"UPDATE tipjar.Tips SET {q} WHERE id = ?", (*kwargs.values(), tip_id)
|
||||||
(*kwargs.values(), tip_id),
|
|
||||||
)
|
)
|
||||||
row = await db.fetchone("SELECT * FROM tipjar.Tips WHERE id = ?", (tip_id,))
|
row = await db.fetchone("SELECT * FROM tipjar.Tips WHERE id = ?", (tip_id,))
|
||||||
assert row, "Newly updated tip couldn't be retrieved"
|
assert row, "Newly updated tip couldn't be retrieved"
|
||||||
|
@ -122,8 +116,7 @@ async def update_tipjar(tipjar_id: str, **kwargs) -> TipJar:
|
||||||
"""Update a tipjar"""
|
"""Update a tipjar"""
|
||||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||||
await db.execute(
|
await db.execute(
|
||||||
f"UPDATE tipjar.TipJars SET {q} WHERE id = ?",
|
f"UPDATE tipjar.TipJars SET {q} WHERE id = ?", (*kwargs.values(), tipjar_id)
|
||||||
(*kwargs.values(), tipjar_id),
|
|
||||||
)
|
)
|
||||||
row = await db.fetchone("SELECT * FROM tipjar.TipJars WHERE id = ?", (tipjar_id,))
|
row = await db.fetchone("SELECT * FROM tipjar.TipJars WHERE id = ?", (tipjar_id,))
|
||||||
assert row, "Newly updated tipjar couldn't be retrieved"
|
assert row, "Newly updated tipjar couldn't be retrieved"
|
||||||
|
|
|
@ -6,10 +6,7 @@ from fastapi.params import Depends
|
||||||
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore
|
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
from lnbits.decorators import (
|
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||||
WalletTypeInfo,
|
|
||||||
get_key_type,
|
|
||||||
)
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
|
|
||||||
from . import tipjar_ext
|
from . import tipjar_ext
|
||||||
|
@ -193,8 +190,7 @@ async def api_delete_tipjar(
|
||||||
tipjar = await get_tipjar(tipjar_id)
|
tipjar = await get_tipjar(tipjar_id)
|
||||||
if not tipjar:
|
if not tipjar:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.NOT_FOUND,
|
status_code=HTTPStatus.NOT_FOUND, detail="No tipjar with this ID!"
|
||||||
detail="No tipjar with this ID!",
|
|
||||||
)
|
)
|
||||||
if tipjar.wallet != g.wallet.id:
|
if tipjar.wallet != g.wallet.id:
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,7 @@ from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_tpos")
|
db = Database("ext_tpos")
|
||||||
|
|
||||||
tpos_ext: APIRouter = APIRouter(
|
tpos_ext: APIRouter = APIRouter(prefix="/tpos", tags=["TPoS"])
|
||||||
prefix="/tpos",
|
|
||||||
tags=["TPoS"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def tpos_renderer():
|
def tpos_renderer():
|
||||||
|
|
|
@ -5,10 +5,7 @@ from lnbits.helpers import template_renderer
|
||||||
|
|
||||||
db = Database("ext_usermanager")
|
db = Database("ext_usermanager")
|
||||||
|
|
||||||
usermanager_ext: APIRouter = APIRouter(
|
usermanager_ext: APIRouter = APIRouter(prefix="/usermanager", tags=["usermanager"])
|
||||||
prefix="/usermanager",
|
|
||||||
tags=["usermanager"]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def usermanager_renderer():
|
def usermanager_renderer():
|
||||||
|
|
|
@ -11,6 +11,7 @@ class CreateUserData(BaseModel):
|
||||||
email: str = Query("")
|
email: str = Query("")
|
||||||
password: str = Query("")
|
password: str = Query("")
|
||||||
|
|
||||||
|
|
||||||
class CreateUserWallet(BaseModel):
|
class CreateUserWallet(BaseModel):
|
||||||
user_id: str = Query(...)
|
user_id: str = Query(...)
|
||||||
wallet_name: str = Query(...)
|
wallet_name: str = Query(...)
|
||||||
|
|
|
@ -93,10 +93,11 @@ async def api_usermanager_activate_extension(
|
||||||
|
|
||||||
@usermanager_ext.post("/api/v1/wallets")
|
@usermanager_ext.post("/api/v1/wallets")
|
||||||
async def api_usermanager_wallets_create(
|
async def api_usermanager_wallets_create(
|
||||||
data: CreateUserWallet,
|
data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type)
|
|
||||||
):
|
):
|
||||||
user = await create_usermanager_wallet(user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id)
|
user = await create_usermanager_wallet(
|
||||||
|
user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id
|
||||||
|
)
|
||||||
return user.dict()
|
return user.dict()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -93,11 +93,12 @@ async def api_lnurl_multi_response(request: Request, unique_hash, id_unique_hash
|
||||||
|
|
||||||
# CALLBACK
|
# CALLBACK
|
||||||
|
|
||||||
|
|
||||||
@withdraw_ext.get(
|
@withdraw_ext.get(
|
||||||
"/api/v1/lnurl/cb/{unique_hash}",
|
"/api/v1/lnurl/cb/{unique_hash}",
|
||||||
status_code=HTTPStatus.OK,
|
status_code=HTTPStatus.OK,
|
||||||
name="withdraw.api_lnurl_callback"
|
name="withdraw.api_lnurl_callback",
|
||||||
)
|
)
|
||||||
async def api_lnurl_callback(
|
async def api_lnurl_callback(
|
||||||
request: Request,
|
request: Request,
|
||||||
unique_hash: str = Query(...),
|
unique_hash: str = Query(...),
|
||||||
|
@ -153,4 +154,3 @@ async def api_lnurl_callback(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await update_withdraw_link(link.id, **changesback)
|
await update_withdraw_link(link.id, **changesback)
|
||||||
return {"status": "ERROR", "reason": "Link not working"}
|
return {"status": "ERROR", "reason": "Link not working"}
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,9 @@ async def api_links(
|
||||||
|
|
||||||
|
|
||||||
@withdraw_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
@withdraw_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||||
async def api_link_retrieve(link_id, request: Request, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_link_retrieve(
|
||||||
|
link_id, request: Request, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||||
|
):
|
||||||
link = await get_withdraw_link(link_id, 0)
|
link = await get_withdraw_link(link_id, 0)
|
||||||
|
|
||||||
if not link:
|
if not link:
|
||||||
|
@ -93,7 +95,9 @@ async def api_link_create_or_update(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN
|
detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN
|
||||||
)
|
)
|
||||||
link = await update_withdraw_link(link_id, **data.dict(), usescsv=usescsv, used=0)
|
link = await update_withdraw_link(
|
||||||
|
link_id, **data.dict(), usescsv=usescsv, used=0
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
link = await create_withdraw_link(
|
link = await create_withdraw_link(
|
||||||
wallet_id=wallet.wallet.id, data=data, usescsv=usescsv
|
wallet_id=wallet.wallet.id, data=data, usescsv=usescsv
|
||||||
|
|
|
@ -234,13 +234,14 @@ async def btc_price(currency: str) -> float:
|
||||||
failures += 1
|
failures += 1
|
||||||
|
|
||||||
if len(rates) >= 2 or len(rates) == 1 and failures >= 2:
|
if len(rates) >= 2 or len(rates) == 1 and failures >= 2:
|
||||||
for t in tasks: t.cancel()
|
for t in tasks:
|
||||||
|
t.cancel()
|
||||||
break
|
break
|
||||||
if failures == len(exchange_rate_providers):
|
if failures == len(exchange_rate_providers):
|
||||||
for t in tasks: t.cancel()
|
for t in tasks:
|
||||||
|
t.cancel()
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
async def fetch_price(provider: Provider):
|
async def fetch_price(provider: Provider):
|
||||||
url = provider.api_url.format(**replacements)
|
url = provider.api_url.format(**replacements)
|
||||||
try:
|
try:
|
||||||
|
@ -251,19 +252,18 @@ async def btc_price(currency: str) -> float:
|
||||||
rate = float(provider.getter(data, replacements))
|
rate = float(provider.getter(data, replacements))
|
||||||
await send_channel.put(rate)
|
await send_channel.put(rate)
|
||||||
except (
|
except (
|
||||||
TypeError, # CoinMate returns HTTPStatus 200 but no data when a currency pair is not found
|
TypeError, # CoinMate returns HTTPStatus 200 but no data when a currency pair is not found
|
||||||
httpx.ConnectTimeout,
|
httpx.ConnectTimeout,
|
||||||
httpx.ConnectError,
|
httpx.ConnectError,
|
||||||
httpx.ReadTimeout,
|
httpx.ReadTimeout,
|
||||||
httpx.HTTPStatusError, # Some providers throw a 404 when a currency pair is not found
|
httpx.HTTPStatusError, # Some providers throw a 404 when a currency pair is not found
|
||||||
):
|
):
|
||||||
await send_channel.put(None)
|
await send_channel.put(None)
|
||||||
|
|
||||||
|
|
||||||
asyncio.create_task(controller())
|
asyncio.create_task(controller())
|
||||||
for _, provider in exchange_rate_providers.items():
|
for _, provider in exchange_rate_providers.items():
|
||||||
tasks.append(asyncio.create_task(fetch_price(provider)))
|
tasks.append(asyncio.create_task(fetch_price(provider)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
|
|
|
@ -139,4 +139,4 @@ class CLightningWallet(Wallet):
|
||||||
wrapped = async_wrap(_paid_invoices_stream)
|
wrapped = async_wrap(_paid_invoices_stream)
|
||||||
paid = await wrapped(self.ln, self.last_pay_index)
|
paid = await wrapped(self.ln, self.last_pay_index)
|
||||||
self.last_pay_index = paid["pay_index"]
|
self.last_pay_index = paid["pay_index"]
|
||||||
yield paid["label"]
|
yield paid["label"]
|
||||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue