Merge pull request #407 from arcbtc/FastAPI

black
This commit is contained in:
Arc 2021-11-12 04:15:27 +00:00 committed by GitHub
commit e9b9197641
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 23219 additions and 13297 deletions

View file

@ -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:

View file

@ -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}

View file

@ -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

View file

@ -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)

View file

@ -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")

View file

@ -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},
) )

View file

@ -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)

View file

@ -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))

View file

@ -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)

View file

@ -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

View file

@ -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(
""" """

View file

@ -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")

View file

@ -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

View file

@ -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,
} },
) )

View file

@ -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"])

View file

@ -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()}
)

View file

@ -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

View file

@ -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),
) )

View file

@ -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()

View file

@ -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}!",
) )

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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,

View file

@ -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()

View file

@ -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

View file

@ -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},
) )

View file

@ -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"])

View file

@ -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)

View file

@ -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

View file

@ -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}
)

View file

@ -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)

View file

@ -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(
""" """

View file

@ -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)

View file

@ -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)

View file

@ -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:

View file

@ -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("")

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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(...)

View file

@ -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
}
) )

View file

@ -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)

View file

@ -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))

View file

@ -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"

View file

@ -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(
""" """

View file

@ -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

View file

@ -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)

View file

@ -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,
} },
) )

View file

@ -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)

View file

@ -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"

View file

@ -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:

View file

@ -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():

View file

@ -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():

View file

@ -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(...)

View file

@ -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()

View file

@ -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"}

View file

@ -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

View file

@ -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:

View file

@ -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