merge main

This commit is contained in:
dni ⚡ 2023-01-04 13:45:18 +01:00
commit 799451ce49
148 changed files with 443 additions and 406 deletions

View File

@ -11,7 +11,11 @@ LNBITS_ALLOWED_USERS=""
LNBITS_ADMIN_USERS="" LNBITS_ADMIN_USERS=""
# Extensions only admin can access # Extensions only admin can access
LNBITS_ADMIN_EXTENSIONS="ngrok, admin" LNBITS_ADMIN_EXTENSIONS="ngrok, admin"
# Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS if available # Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS if available
# Warning: Enabling this will make LNbits ignore this configuration file. Your settings will
# be stored in your database and you will be able to change them only through the Admin UI.
# Disable this to make LNbits use this config file again.
LNBITS_ADMIN_UI=false LNBITS_ADMIN_UI=false
LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" LNBITS_DEFAULT_WALLET_NAME="LNbits wallet"

View File

@ -25,7 +25,7 @@ LNbits is a very simple Python server that sits on top of any funding source, an
LNbits can run on top of any lightning-network funding source, currently there is support for LND, c-lightning, Spark, LNpay, OpenNode, lntxbot, with more being added regularly. LNbits can run on top of any lightning-network funding source, currently there is support for LND, c-lightning, Spark, LNpay, OpenNode, lntxbot, with more being added regularly.
See [legend.lnbits.org](https://legend.lnbits.org) for more detailed documentation. See [docs.lnbits.org](https://docs.lnbits.org) for more detailed documentation.
Checkout the LNbits [YouTube](https://www.youtube.com/playlist?list=PLPj3KCksGbSYG0ciIQUWJru1dWstPHshe) video series. Checkout the LNbits [YouTube](https://www.youtube.com/playlist?list=PLPj3KCksGbSYG0ciIQUWJru1dWstPHshe) video series.
@ -70,7 +70,7 @@ Wallets can be easily generated and given out to people at events (one click mul
If you like this project and might even use or extend it, why not [send some tip love](https://legend.lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK)! If you like this project and might even use or extend it, why not [send some tip love](https://legend.lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK)!
[docs]: https://legend.lnbits.org/ [docs]: https://docs.lnbits.org/
[docs-badge]: https://img.shields.io/badge/docs-lnbits.org-673ab7.svg [docs-badge]: https://img.shields.io/badge/docs-lnbits.org-673ab7.svg
[github-mypy]: https://github.com/lnbits/lnbits/actions?query=workflow%3Amypy [github-mypy]: https://github.com/lnbits/lnbits/actions?query=workflow%3Amypy
[github-mypy-badge]: https://github.com/lnbits/lnbits/workflows/mypy/badge.svg [github-mypy-badge]: https://github.com/lnbits/lnbits/workflows/mypy/badge.svg

View File

@ -1 +1 @@
legend.lnbits.org docs.lnbits.org

View File

@ -3,7 +3,7 @@ remote_theme: pmarsceill/just-the-docs
color_scheme: dark color_scheme: dark
logo: "/logos/lnbits-full--inverse.png" logo: "/logos/lnbits-full--inverse.png"
search_enabled: true search_enabled: true
url: https://legend.lnbits.org url: https://docs.lnbits.org
aux_links: aux_links:
"LNbits on GitHub": "LNbits on GitHub":
- "//github.com/lnbits/lnbits" - "//github.com/lnbits/lnbits"

View File

@ -9,4 +9,4 @@ nav_order: 3
API reference API reference
============= =============
[Swagger Docs](https://legend.lnbits.org/devs/swagger.html) [Swagger Docs](https://docs.lnbits.org/devs/swagger.html)

View File

@ -74,7 +74,7 @@ def decode(pr: str) -> Invoice:
data_length = len(tagdata) / 5 data_length = len(tagdata) / 5
if tag == "d": if tag == "d":
invoice.description = _trim_to_bytes(tagdata).decode("utf-8") invoice.description = _trim_to_bytes(tagdata).decode()
elif tag == "h" and data_length == 52: elif tag == "h" and data_length == 52:
invoice.description_hash = _trim_to_bytes(tagdata).hex() invoice.description_hash = _trim_to_bytes(tagdata).hex()
elif tag == "p" and data_length == 52: elif tag == "p" and data_length == 52:
@ -260,7 +260,7 @@ class LnAddr(object):
def __str__(self): def __str__(self):
return "LnAddr[{}, amount={}{} tags=[{}]]".format( return "LnAddr[{}, amount={}{} tags=[{}]]".format(
bytes.hex(self.pubkey.serialize()).decode("utf-8"), bytes.hex(self.pubkey.serialize()).decode(),
self.amount, self.amount,
self.currency, self.currency,
", ".join([k + "=" + str(v) for k, v in self.tags]), ", ".join([k + "=" + str(v) for k, v in self.tags]),

View File

@ -46,8 +46,8 @@ class Wallet(BaseModel):
return "" return ""
def lnurlauth_key(self, domain: str) -> SigningKey: def lnurlauth_key(self, domain: str) -> SigningKey:
hashing_key = hashlib.sha256(self.id.encode("utf-8")).digest() hashing_key = hashlib.sha256(self.id.encode()).digest()
linking_key = hmac.digest(hashing_key, domain.encode("utf-8"), "sha256") linking_key = hmac.digest(hashing_key, domain.encode(), "sha256")
return SigningKey.from_string( return SigningKey.from_string(
linking_key, curve=SECP256k1, hashfunc=hashlib.sha256 linking_key, curve=SECP256k1, hashfunc=hashlib.sha256

View File

@ -23,14 +23,55 @@
> >
<q-card> <q-card>
<q-card-section> <q-card-section>
<q-icon <div class="row">
:name="extension.icon" <div class="col-3">
color="grey-5" <q-img
style="font-size: 4rem" :src="extension.tile"
></q-icon> spinner-color="white"
{% raw %} style="max-width: 100%"
<h5 class="q-mt-lg q-mb-xs">{{ extension.name }}</h5> ></q-img>
<small>{{ extension.shortDescription }} </small>{% endraw %} </div>
<div class="col-9 q-pl-sm">
{% raw %}
<div class="text-h5 gt-sm q-mt-sm q-mb-xs">
{{ extension.name }}
</div>
<div
class="text-subtitle2 gt-sm"
style="font-size: 11px; height: 34px"
>
{{ extension.shortDescription }}
</div>
<div class="text-subtitle1 lt-md q-mt-sm q-mb-xs">
{{ extension.name }}
</div>
<div
class="text-subtitle2 lt-md"
style="font-size: 9px; height: 34px"
>
{{ extension.shortDescription }}
</div>
{% endraw %}
</div>
</div>
</q-card-section>
<q-card-section>
<div>
<q-rating
class="gt-sm"
disable
size="2em"
:max="5"
color="primary"
></q-rating
><q-rating
class="lt-md"
size="1.5em"
:max="5"
color="primary"
></q-rating
><q-tooltip>Ratings coming soon</q-tooltip>
</div>
</q-card-section> </q-card-section>
<q-separator></q-separator> <q-separator></q-separator>
<q-card-actions> <q-card-actions>

View File

@ -23,7 +23,7 @@
<strong>{% raw %}{{ formattedBalance }} {% endraw %}</strong> <strong>{% raw %}{{ formattedBalance }} {% endraw %}</strong>
{{LNBITS_DENOMINATION}} {{LNBITS_DENOMINATION}}
<q-btn <q-btn
v-if="'{{user.admin}}' == 'True'" v-if="'{{user.super_user}}' == 'True'"
flat flat
round round
color="primary" color="primary"
@ -36,27 +36,16 @@
v-model="credit" v-model="credit"
> >
<q-input <q-input
v-if="'{{LNBITS_DENOMINATION}}' != 'sats'" filled
label="Amount to credit account" label="{{LNBITS_DENOMINATION}} to credit"
hint="Press Enter to credit account"
v-model="scope.value" v-model="scope.value"
dense dense
autofocus autofocus
mask="#.##" :mask="'{{LNBITS_DENOMINATION}}' != 'sats' ? '#.##' : '#'"
fill-mask="0" fill-mask="0"
reverse-fill-mask reverse-fill-mask
@keyup.enter="updateBalance(scope.value)" :step="'{{LNBITS_DENOMINATION}}' != 'sats' ? '0.01' : '1'"
>
<template v-slot:append>
<q-icon name="edit" />
</template>
</q-input>
<q-input
v-else
type="number"
label="Amount to credit account"
v-model="scope.value"
dense
autofocus
@keyup.enter="updateBalance(scope.value)" @keyup.enter="updateBalance(scope.value)"
> >
<template v-slot:append> <template v-slot:append>
@ -479,10 +468,10 @@
dense dense
v-model.number="receive.data.amount" v-model.number="receive.data.amount"
:label="'Amount (' + receive.unit + ') *'" :label="'Amount (' + receive.unit + ') *'"
:mask="receive.unit != 'sat' ? '#.##' : '#'" :mask="receive.unit != 'sats' ? '#.##' : '#'"
fill-mask="0" fill-mask="0"
reverse-fill-mask reverse-fill-mask
:step="receive.unit != 'sat' ? '0.01' : '1'" :step="receive.unit != 'sats' ? '0.01' : '1'"
:min="receive.minMax[0]" :min="receive.minMax[0]"
:max="receive.minMax[1]" :max="receive.minMax[1]"
:readonly="receive.lnurl && receive.lnurl.fixed" :readonly="receive.lnurl && receive.lnurl.fixed"

View File

@ -17,7 +17,7 @@ from ..crud import delete_admin_settings, get_admin_settings, update_admin_setti
@core_app.get("/admin/api/v1/settings/") @core_app.get("/admin/api/v1/settings/")
async def api_get_settings( async def api_get_settings(
user: User = Depends(check_admin), # type: ignore user: User = Depends(check_admin),
) -> Optional[AdminSettings]: ) -> Optional[AdminSettings]:
admin_settings = await get_admin_settings(user.super_user) admin_settings = await get_admin_settings(user.super_user)
return admin_settings return admin_settings

View File

@ -12,6 +12,7 @@ import async_timeout
import httpx import httpx
import pyqrcode import pyqrcode
from fastapi import ( from fastapi import (
Body,
Depends, Depends,
Header, Header,
Query, Query,
@ -21,7 +22,6 @@ from fastapi import (
WebSocketDisconnect, WebSocketDisconnect,
) )
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
from fastapi.params import Body
from loguru import logger from loguru import logger
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.fields import Field from pydantic.fields import Field
@ -251,7 +251,7 @@ async def api_payments_pay_invoice(bolt11: str, wallet: Wallet):
) )
async def api_payments_create( async def api_payments_create(
wallet: WalletTypeInfo = Depends(require_invoice_key), wallet: WalletTypeInfo = Depends(require_invoice_key),
invoiceData: CreateInvoiceData = Body(...), # type: ignore invoiceData: CreateInvoiceData = Body(...),
): ):
if invoiceData.out is True and wallet.wallet_type == 0: if invoiceData.out is True and wallet.wallet_type == 0:
if not invoiceData.bolt11: if not invoiceData.bolt11:
@ -387,7 +387,7 @@ async def subscribe_wallet_invoices(request: Request, wallet: Wallet):
jdata = json.dumps(dict(data.dict(), pending=False)) jdata = json.dumps(dict(data.dict(), pending=False))
yield dict(data=jdata, event=typ) yield dict(data=jdata, event=typ)
except asyncio.CancelledError as e: except asyncio.CancelledError:
logger.debug(f"removing listener for wallet {uid}") logger.debug(f"removing listener for wallet {uid}")
api_invoice_listeners.pop(uid) api_invoice_listeners.pop(uid)
task.cancel() task.cancel()
@ -536,7 +536,7 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type
params.update( params.update(
description_hash=hashlib.sha256( description_hash=hashlib.sha256(
data["metadata"].encode("utf-8") data["metadata"].encode()
).hexdigest() ).hexdigest()
) )
metadata = json.loads(data["metadata"]) metadata = json.loads(data["metadata"])

View File

@ -2,9 +2,8 @@ import asyncio
from http import HTTPStatus from http import HTTPStatus
from typing import Optional from typing import Optional
from fastapi import Request, status from fastapi import Depends, Query, Request, status
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
from fastapi.params import Depends, Query
from fastapi.responses import FileResponse, RedirectResponse from fastapi.responses import FileResponse, RedirectResponse
from fastapi.routing import APIRouter from fastapi.routing import APIRouter
from loguru import logger from loguru import logger
@ -49,9 +48,9 @@ async def home(request: Request, lightning: str = ""):
) )
async def extensions( async def extensions(
request: Request, request: Request,
user: User = Depends(check_user_exists), # type: ignore user: User = Depends(check_user_exists),
enable: str = Query(None), # type: ignore enable: str = Query(None),
disable: str = Query(None), # type: ignore disable: str = Query(None),
): ):
extension_to_enable = enable extension_to_enable = enable
extension_to_disable = disable extension_to_disable = disable
@ -103,10 +102,10 @@ nothing: create everything<br>
""", """,
) )
async def wallet( async def wallet(
request: Request = Query(None), # type: ignore request: Request = Query(None),
nme: Optional[str] = Query(None), # type: ignore nme: Optional[str] = Query(None),
usr: Optional[UUID4] = Query(None), # type: ignore usr: Optional[UUID4] = Query(None),
wal: Optional[UUID4] = Query(None), # type: ignore wal: Optional[UUID4] = Query(None),
): ):
user_id = usr.hex if usr else None user_id = usr.hex if usr else None
wallet_id = wal.hex if wal else None wallet_id = wal.hex if wal else None
@ -132,6 +131,8 @@ async def wallet(
) )
if user_id == settings.super_user or user_id in settings.lnbits_admin_users: if user_id == settings.super_user or user_id in settings.lnbits_admin_users:
user.admin = True user.admin = True
if user_id == settings.super_user:
user.super_user = True
if not wallet_id: if not wallet_id:
if user.wallets and not wallet_name: # type: ignore if user.wallets and not wallet_name: # type: ignore
@ -217,7 +218,7 @@ async def lnurl_full_withdraw_callback(request: Request):
@core_html_routes.get("/deletewallet", response_class=RedirectResponse) @core_html_routes.get("/deletewallet", response_class=RedirectResponse)
async def deletewallet(request: Request, wal: str = Query(...), usr: str = Query(...)): # type: ignore async def deletewallet(wal: str = Query(...), usr: str = Query(...)):
user = await get_user(usr) user = await get_user(usr)
user_wallet_ids = [u.id for u in user.wallets] # type: ignore user_wallet_ids = [u.id for u in user.wallets] # type: ignore
@ -313,7 +314,7 @@ async def manifest(usr: str):
@core_html_routes.get("/admin", response_class=HTMLResponse) @core_html_routes.get("/admin", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_admin)): # type: ignore async def index(request: Request, user: User = Depends(check_admin)):
WALLET = get_wallet_class() WALLET = get_wallet_class()
_, balance = await WALLET.status() _, balance = await WALLET.status()

View File

@ -1,11 +1,8 @@
from http import HTTPStatus from http import HTTPStatus
from typing import Union
from cerberus import Validator # type: ignore from fastapi import Security, status
from fastapi import status
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
from fastapi.openapi.models import APIKey, APIKeyIn from fastapi.openapi.models import APIKey, APIKeyIn
from fastapi.params import Security
from fastapi.security.api_key import APIKeyHeader, APIKeyQuery from fastapi.security.api_key import APIKeyHeader, APIKeyQuery
from fastapi.security.base import SecurityBase from fastapi.security.base import SecurityBase
from pydantic.types import UUID4 from pydantic.types import UUID4
@ -118,8 +115,8 @@ api_key_query = APIKeyQuery(
async def get_key_type( async def get_key_type(
r: Request, r: Request,
api_key_header: str = Security(api_key_header), # type: ignore api_key_header: str = Security(api_key_header),
api_key_query: str = Security(api_key_query), # type: ignore api_key_query: str = Security(api_key_query),
) -> WalletTypeInfo: ) -> WalletTypeInfo:
# 0: admin # 0: admin
# 1: invoice # 1: invoice
@ -174,8 +171,8 @@ async def get_key_type(
async def require_admin_key( async def require_admin_key(
r: Request, r: Request,
api_key_header: str = Security(api_key_header), # type: ignore api_key_header: str = Security(api_key_header),
api_key_query: str = Security(api_key_query), # type: ignore api_key_query: str = Security(api_key_query),
): ):
token = api_key_header or api_key_query token = api_key_header or api_key_query
@ -200,8 +197,8 @@ async def require_admin_key(
async def require_invoice_key( async def require_invoice_key(
r: Request, r: Request,
api_key_header: str = Security(api_key_header), # type: ignore api_key_header: str = Security(api_key_header),
api_key_query: str = Security(api_key_query), # type: ignore api_key_query: str = Security(api_key_query),
): ):
token = api_key_header or api_key_query token = api_key_header or api_key_query

View File

@ -1,6 +1,6 @@
{ {
"name": "Bleskomat", "name": "Bleskomat",
"short_description": "Connect a Bleskomat ATM to an lnbits", "short_description": "Connect a Bleskomat ATM to an lnbits",
"icon": "money", "tile": "/bleskomat/static/image/bleskomat.png",
"contributors": ["chill117"] "contributors": ["chill117"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "Bolt Cards", "name": "Bolt Cards",
"short_description": "Self custody Bolt Cards with one time LNURLw", "short_description": "Self custody Bolt Cards with one time LNURLw",
"icon": "payment", "tile": "/boltcards/static/image/boltcard.png",
"contributors": ["iwarpbtc", "arcbtc", "leesalminen"] "contributors": ["iwarpbtc", "arcbtc", "leesalminen"]
} }

View File

@ -213,7 +213,7 @@ async def lnurlp_callback(
memo=f"Refund {hit_id}", memo=f"Refund {hit_id}",
unhashed_description=LnurlPayMetadata( unhashed_description=LnurlPayMetadata(
json.dumps([["text/plain", "Refund"]]) json.dumps([["text/plain", "Refund"]])
).encode("utf-8"), ).encode(),
extra={"refund": hit_id}, extra={"refund": hit_id},
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from fastapi import APIRouter from fastapi import APIRouter
from fastapi.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -15,6 +16,14 @@ def boltz_renderer():
return template_renderer(["lnbits/extensions/boltz/templates"]) return template_renderer(["lnbits/extensions/boltz/templates"])
boltz_static_files = [
{
"path": "/boltz/static",
"app": StaticFiles(directory="lnbits/extensions/boltz/static"),
"name": "boltz_static",
}
]
from .tasks import check_for_pending_swaps, wait_for_paid_invoices from .tasks import check_for_pending_swaps, wait_for_paid_invoices
from .views import * # noqa from .views import * # noqa
from .views_api import * # noqa from .views_api import * # noqa

View File

@ -55,7 +55,7 @@ async def create_swap(data: CreateSubmarineSwap) -> SubmarineSwap:
raise raise
refund_privkey = ec.PrivateKey(os.urandom(32), True, net) refund_privkey = ec.PrivateKey(os.urandom(32), True, net)
refund_pubkey_hex = bytes.hex(refund_privkey.sec()).decode("UTF-8") refund_pubkey_hex = bytes.hex(refund_privkey.sec()).decode()
res = req_wrap( res = req_wrap(
"post", "post",
@ -120,7 +120,7 @@ async def create_reverse_swap(
return False return False
claim_privkey = ec.PrivateKey(os.urandom(32), True, net) claim_privkey = ec.PrivateKey(os.urandom(32), True, net)
claim_pubkey_hex = bytes.hex(claim_privkey.sec()).decode("UTF-8") claim_pubkey_hex = bytes.hex(claim_privkey.sec()).decode()
preimage = os.urandom(32) preimage = os.urandom(32)
preimage_hash = sha256(preimage).hexdigest() preimage_hash = sha256(preimage).hexdigest()

View File

@ -1,6 +1,6 @@
{ {
"name": "Boltz", "name": "Boltz",
"short_description": "Perform onchain/offchain swaps", "short_description": "Perform onchain/offchain swaps",
"icon": "swap_horiz", "tile": "/boltz/static/image/boltz.png",
"contributors": ["dni"] "contributors": ["dni"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -1,7 +1,7 @@
{ {
"name": "Cashu", "name": "Cashu",
"short_description": "Ecash mint and wallet", "short_description": "Ecash mint and wallet",
"icon": "account_balance", "tile": "/cashu/static/image/cashu.png",
"contributors": ["calle", "vlad", "arcbtc"], "contributors": ["calle", "vlad", "arcbtc"],
"hidden": false "hidden": false
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,7 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
@ -18,7 +17,7 @@ templates = Jinja2Templates(directory="templates")
@cashu_ext.get("/", response_class=HTMLResponse) @cashu_ext.get("/", response_class=HTMLResponse)
async def index( async def index(
request: Request, request: Request,
user: User = Depends(check_user_exists), # type: ignore user: User = Depends(check_user_exists),
): ):
return cashu_renderer().TemplateResponse( return cashu_renderer().TemplateResponse(
"cashu/index.html", {"request": request, "user": user.dict()} "cashu/index.html", {"request": request, "user": user.dict()}

View File

@ -1,10 +1,7 @@
import json
import math import math
from http import HTTPStatus from http import HTTPStatus
from typing import Dict, List, Union from typing import Dict, List, Union
import httpx
# -------- cashu imports # -------- cashu imports
from cashu.core.base import ( from cashu.core.base import (
BlindedSignature, BlindedSignature,
@ -17,14 +14,10 @@ from cashu.core.base import (
MeltRequest, MeltRequest,
MintRequest, MintRequest,
PostSplitResponse, PostSplitResponse,
Proof,
SplitRequest, SplitRequest,
) )
from fastapi import Query from fastapi import Depends, Query
from fastapi.params import Depends
from lnurl import decode as decode_lnurl
from loguru import logger from loguru import logger
from secp256k1 import PublicKey
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits import bolt11 from lnbits import bolt11
@ -35,7 +28,6 @@ from lnbits.core.services import (
fee_reserve, fee_reserve,
pay_invoice, pay_invoice,
) )
from lnbits.core.views.api import api_payment
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
from lnbits.helpers import urlsafe_short_hash from lnbits.helpers import urlsafe_short_hash
from lnbits.wallets.base import PaymentStatus from lnbits.wallets.base import PaymentStatus
@ -63,7 +55,7 @@ if not LIGHTNING:
@cashu_ext.get("/api/v1/mints", status_code=HTTPStatus.OK) @cashu_ext.get("/api/v1/mints", status_code=HTTPStatus.OK)
async def api_cashus( async def api_cashus(
all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)
): ):
""" """
Get all mints of this wallet. Get all mints of this wallet.
@ -80,7 +72,7 @@ async def api_cashus(
@cashu_ext.post("/api/v1/mints", status_code=HTTPStatus.CREATED) @cashu_ext.post("/api/v1/mints", status_code=HTTPStatus.CREATED)
async def api_cashu_create( async def api_cashu_create(
data: Cashu, data: Cashu,
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
): ):
""" """
Create a new mint for this wallet. Create a new mint for this wallet.
@ -98,7 +90,7 @@ async def api_cashu_create(
@cashu_ext.delete("/api/v1/mints/{cashu_id}") @cashu_ext.delete("/api/v1/mints/{cashu_id}")
async def api_cashu_delete( async def api_cashu_delete(
cashu_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) # type: ignore cashu_id: str, wallet: WalletTypeInfo = Depends(require_admin_key)
): ):
""" """
Delete an existing cashu mint. Delete an existing cashu mint.

View File

@ -1,7 +1,7 @@
{ {
"name": "Streamer Copilot", "name": "Streamer Copilot",
"short_description": "Video tips/animations/webhooks", "short_description": "Video tips/animations/webhooks",
"icon": "face", "tile": "/copilot/static/bitcoin-streaming.png",
"contributors": [ "contributors": [
"arcbtc" "arcbtc"
] ]

View File

@ -75,7 +75,7 @@ async def lnurl_callback(
memo=cp.lnurl_title, memo=cp.lnurl_title,
unhashed_description=( unhashed_description=(
LnurlPayMetadata(json.dumps([["text/plain", str(cp.lnurl_title)]])) LnurlPayMetadata(json.dumps([["text/plain", str(cp.lnurl_title)]]))
).encode("utf-8"), ).encode(),
extra={"tag": "copilot", "copilotid": cp.id, "comment": comment}, extra={"tag": "copilot", "copilotid": cp.id, "comment": comment},
) )
payResponse = {"pr": payment_request, "routes": []} payResponse = {"pr": payment_request, "routes": []}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -1,7 +1,6 @@
from typing import List from typing import List
from fastapi import Request, WebSocket, WebSocketDisconnect from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.responses import HTMLResponse # type: ignore from starlette.responses import HTMLResponse # type: ignore
@ -9,15 +8,12 @@ from lnbits.core.models import User
from lnbits.decorators import check_user_exists from lnbits.decorators import check_user_exists
from . import copilot_ext, copilot_renderer from . import copilot_ext, copilot_renderer
from .crud import get_copilot
templates = Jinja2Templates(directory="templates") templates = Jinja2Templates(directory="templates")
@copilot_ext.get("/", response_class=HTMLResponse) @copilot_ext.get("/", response_class=HTMLResponse)
async def index( async def index(request: Request, user: User = Depends(check_user_exists)):
request: Request, user: User = Depends(check_user_exists) # type: ignore
):
return copilot_renderer().TemplateResponse( return copilot_renderer().TemplateResponse(
"copilot/index.html", {"request": request, "user": user.dict()} "copilot/index.html", {"request": request, "user": user.dict()}
) )

View File

@ -1,8 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, Query, Request
from fastapi.param_functions import Query
from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits.core.services import websocketUpdater from lnbits.core.services import websocketUpdater
@ -22,9 +20,7 @@ from .models import CreateCopilotData
@copilot_ext.get("/api/v1/copilot") @copilot_ext.get("/api/v1/copilot")
async def api_copilots_retrieve( async def api_copilots_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
req: Request, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore
):
wallet_user = wallet.wallet.user wallet_user = wallet.wallet.user
copilots = [copilot.dict() for copilot in await get_copilots(wallet_user)] copilots = [copilot.dict() for copilot in await get_copilots(wallet_user)]
try: try:
@ -37,7 +33,7 @@ async def api_copilots_retrieve(
async def api_copilot_retrieve( async def api_copilot_retrieve(
req: Request, req: Request,
copilot_id: str = Query(None), copilot_id: str = Query(None),
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
): ):
copilot = await get_copilot(copilot_id) copilot = await get_copilot(copilot_id)
if not copilot: if not copilot:
@ -54,7 +50,7 @@ async def api_copilot_retrieve(
async def api_copilot_create_or_update( async def api_copilot_create_or_update(
data: CreateCopilotData, data: CreateCopilotData,
copilot_id: str = Query(None), copilot_id: str = Query(None),
wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore wallet: WalletTypeInfo = Depends(require_admin_key),
): ):
data.user = wallet.wallet.user data.user = wallet.wallet.user
data.wallet = wallet.wallet.id data.wallet = wallet.wallet.id
@ -68,7 +64,7 @@ async def api_copilot_create_or_update(
@copilot_ext.delete("/api/v1/copilot/{copilot_id}") @copilot_ext.delete("/api/v1/copilot/{copilot_id}")
async def api_copilot_delete( async def api_copilot_delete(
copilot_id: str = Query(None), copilot_id: str = Query(None),
wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore wallet: WalletTypeInfo = Depends(require_admin_key),
): ):
copilot = await get_copilot(copilot_id) copilot = await get_copilot(copilot_id)

View File

@ -1,6 +1,6 @@
{ {
"name": "Discord Bot", "name": "Discord Bot",
"short_description": "Generate users and wallets", "short_description": "Generate users and wallets",
"icon": "person_add", "tile": "/discordbot/static/image/discordbot.png",
"contributors": ["bitcoingamer21"] "contributors": ["bitcoingamer21"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,5 +1,4 @@
from fastapi import Request from fastapi import Depends, Request
from fastapi.params import Depends
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
from lnbits.core.models import User from lnbits.core.models import User
@ -9,9 +8,7 @@ from . import discordbot_ext, discordbot_renderer
@discordbot_ext.get("/", response_class=HTMLResponse) @discordbot_ext.get("/", response_class=HTMLResponse)
async def index( async def index(request: Request, user: User = Depends(check_user_exists)):
request: Request, user: User = Depends(check_user_exists) # type: ignore
):
return discordbot_renderer().TemplateResponse( return discordbot_renderer().TemplateResponse(
"discordbot/index.html", {"request": request, "user": user.dict()} "discordbot/index.html", {"request": request, "user": user.dict()}
) )

View File

@ -1,7 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Query from fastapi import Depends, Query
from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits.core import update_user_extension from lnbits.core import update_user_extension
@ -28,16 +27,14 @@ from .models import CreateUserData, CreateUserWallet
@discordbot_ext.get("/api/v1/users", status_code=HTTPStatus.OK) @discordbot_ext.get("/api/v1/users", status_code=HTTPStatus.OK)
async def api_discordbot_users( async def api_discordbot_users(
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
): ):
user_id = wallet.wallet.user user_id = wallet.wallet.user
return [user.dict() for user in await get_discordbot_users(user_id)] return [user.dict() for user in await get_discordbot_users(user_id)]
@discordbot_ext.get("/api/v1/users/{user_id}", status_code=HTTPStatus.OK) @discordbot_ext.get("/api/v1/users/{user_id}", status_code=HTTPStatus.OK)
async def api_discordbot_user( async def api_discordbot_user(user_id, wallet: WalletTypeInfo = Depends(get_key_type)):
user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore
):
user = await get_discordbot_user(user_id) user = await get_discordbot_user(user_id)
if user: if user:
return user.dict() return user.dict()
@ -45,7 +42,7 @@ async def api_discordbot_user(
@discordbot_ext.post("/api/v1/users", status_code=HTTPStatus.CREATED) @discordbot_ext.post("/api/v1/users", status_code=HTTPStatus.CREATED)
async def api_discordbot_users_create( async def api_discordbot_users_create(
data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
user = await create_discordbot_user(data) user = await create_discordbot_user(data)
full = user.dict() full = user.dict()
@ -57,7 +54,7 @@ async def api_discordbot_users_create(
@discordbot_ext.delete("/api/v1/users/{user_id}") @discordbot_ext.delete("/api/v1/users/{user_id}")
async def api_discordbot_users_delete( async def api_discordbot_users_delete(
user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore user_id, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
user = await get_discordbot_user(user_id) user = await get_discordbot_user(user_id)
if not user: if not user:
@ -89,7 +86,7 @@ async def api_discordbot_activate_extension(
@discordbot_ext.post("/api/v1/wallets") @discordbot_ext.post("/api/v1/wallets")
async def api_discordbot_wallets_create( async def api_discordbot_wallets_create(
data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
user = await create_discordbot_wallet( user = await create_discordbot_wallet(
user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id
@ -99,7 +96,7 @@ async def api_discordbot_wallets_create(
@discordbot_ext.get("/api/v1/wallets") @discordbot_ext.get("/api/v1/wallets")
async def api_discordbot_wallets( async def api_discordbot_wallets(
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
): ):
admin_id = wallet.wallet.user admin_id = wallet.wallet.user
return await get_discordbot_wallets(admin_id) return await get_discordbot_wallets(admin_id)
@ -107,21 +104,21 @@ async def api_discordbot_wallets(
@discordbot_ext.get("/api/v1/transactions/{wallet_id}") @discordbot_ext.get("/api/v1/transactions/{wallet_id}")
async def api_discordbot_wallet_transactions( async def api_discordbot_wallet_transactions(
wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore wallet_id, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
return await get_discordbot_wallet_transactions(wallet_id) return await get_discordbot_wallet_transactions(wallet_id)
@discordbot_ext.get("/api/v1/wallets/{user_id}") @discordbot_ext.get("/api/v1/wallets/{user_id}")
async def api_discordbot_users_wallets( async def api_discordbot_users_wallets(
user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore user_id, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
return await get_discordbot_users_wallets(user_id) return await get_discordbot_users_wallets(user_id)
@discordbot_ext.delete("/api/v1/wallets/{wallet_id}") @discordbot_ext.delete("/api/v1/wallets/{wallet_id}")
async def api_discordbot_wallets_delete( async def api_discordbot_wallets_delete(
wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore wallet_id, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
get_wallet = await get_discordbot_wallet(wallet_id) get_wallet = await get_discordbot_wallet(wallet_id)
if not get_wallet: if not get_wallet:

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from fastapi import APIRouter from fastapi import APIRouter
from fastapi.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -11,6 +12,14 @@ db = Database("ext_events")
events_ext: APIRouter = APIRouter(prefix="/events", tags=["Events"]) events_ext: APIRouter = APIRouter(prefix="/events", tags=["Events"])
events_static_files = [
{
"path": "/events/static",
"app": StaticFiles(packages=[("lnbits", "extensions/events/static")]),
"name": "events_static",
}
]
def events_renderer(): def events_renderer():
return template_renderer(["lnbits/extensions/events/templates"]) return template_renderer(["lnbits/extensions/events/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "Events", "name": "Events",
"short_description": "Sell and register event tickets", "short_description": "Sell and register event tickets",
"icon": "local_activity", "tile": "/events/static/image/events.png",
"contributors": ["benarc"] "contributors": ["benarc"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -1,15 +1,6 @@
import asyncio import asyncio
import json
from http import HTTPStatus
from urllib.parse import urlparse
import httpx
from fastapi import HTTPException
from loguru import logger
from lnbits import bolt11
from lnbits.core.models import Payment from lnbits.core.models import Payment
from lnbits.core.services import pay_invoice
from lnbits.extensions.events.models import CreateTicket from lnbits.extensions.events.models import CreateTicket
from lnbits.helpers import get_current_extension_name from lnbits.helpers import get_current_extension_name
from lnbits.tasks import register_invoice_listener from lnbits.tasks import register_invoice_listener
@ -29,11 +20,17 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
# (avoid loops) # (avoid loops)
if ( if (
"events" == payment.extra.get("tag") payment.extra
and "events" == payment.extra.get("tag")
and payment.extra.get("name") and payment.extra.get("name")
and payment.extra.get("email") and payment.extra.get("email")
): ):
CreateTicket.name = str(payment.extra.get("name")) await api_ticket_send_ticket(
CreateTicket.email = str(payment.extra.get("email")) payment.memo,
await api_ticket_send_ticket(payment.memo, payment.payment_hash, CreateTicket) payment.payment_hash,
CreateTicket(
name=str(payment.extra.get("name")),
email=str(payment.extra.get("email")),
),
)
return return

View File

@ -1,8 +1,7 @@
from datetime import date, datetime from datetime import date, datetime
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse

View File

@ -1,10 +1,7 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi.param_functions import Query from fastapi import Depends, Query
from fastapi.params import Depends
from loguru import logger
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.requests import Request
from lnbits.core.crud import get_user from lnbits.core.crud import get_user
from lnbits.core.services import create_invoice from lnbits.core.services import create_invoice
@ -38,7 +35,8 @@ async def api_events(
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [event.dict() for event in await get_events(wallet_ids)] return [event.dict() for event in await get_events(wallet_ids)]
@ -92,7 +90,8 @@ async def api_tickets(
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [ticket.dict() for ticket in await get_tickets(wallet_ids)] return [ticket.dict() for ticket in await get_tickets(wallet_ids)]
@ -119,26 +118,32 @@ async def api_ticket_make_ticket(event_id, name, email):
@events_ext.post("/api/v1/tickets/{event_id}/{payment_hash}") @events_ext.post("/api/v1/tickets/{event_id}/{payment_hash}")
async def api_ticket_send_ticket(event_id, payment_hash, data: CreateTicket): async def api_ticket_send_ticket(event_id, payment_hash, data: CreateTicket):
event = await get_event(event_id) event = await get_event(event_id)
try: if not event:
status = await api_payment(payment_hash) raise HTTPException(
if status["paid"]: status_code=HTTPStatus.NOT_FOUND,
ticket = await create_ticket( detail=f"Event could not be fetched.",
payment_hash=payment_hash, )
wallet=event.wallet,
event=event_id, status = await api_payment(payment_hash)
name=data.name, if status["paid"]:
email=data.email,
exists = await get_ticket(payment_hash)
if exists:
return {"paid": True, "ticket_id": exists.id}
ticket = await create_ticket(
payment_hash=payment_hash,
wallet=event.wallet,
event=event_id,
name=data.name,
email=data.email,
)
if not ticket:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail=f"Event could not be fetched.",
) )
return {"paid": True, "ticket_id": ticket.id}
if not ticket:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND,
detail=f"Event could not be fetched.",
)
return {"paid": True, "ticket_id": ticket.id}
except Exception:
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Not paid")
return {"paid": False} return {"paid": False}

View File

@ -1,6 +1,6 @@
{ {
"name": "Build your own!!", "name": "Build your own!!",
"short_description": "Join us, make an extension", "short_description": "Join us, make an extension",
"icon": "info", "tile": "/cashu/static/image/tile.png",
"contributors": ["github_username"] "contributors": ["github_username"]
} }

View File

@ -1,5 +1,4 @@
from fastapi import FastAPI, Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
@ -14,7 +13,7 @@ templates = Jinja2Templates(directory="templates")
@example_ext.get("/", response_class=HTMLResponse) @example_ext.get("/", response_class=HTMLResponse)
async def index( async def index(
request: Request, request: Request,
user: User = Depends(check_user_exists), # type: ignore user: User = Depends(check_user_exists),
): ):
return example_renderer().TemplateResponse( return example_renderer().TemplateResponse(
"example/index.html", {"request": request, "user": user.dict()} "example/index.html", {"request": request, "user": user.dict()}

View File

@ -1,6 +1,6 @@
{ {
"name": "Gerty", "name": "Gerty",
"short_description": "Desktop bitcoin Assistant", "short_description": "Desktop bitcoin Assistant",
"icon": "sentiment_satisfied", "tile": "/gerty/static/gerty.png",
"contributors": ["arcbtc", "blackcoffeebtc"] "contributors": ["arcbtc", "blackcoffeebtc"]
} }

View File

@ -117,7 +117,7 @@ async def get_mempool_info(endPoint: str, gerty) -> dict:
mempool_id, mempool_id,
json.dumps(response.json()), json.dumps(response.json()),
endPoint, endPoint,
int(time.time()), time.time(),
gerty.mempool_endpoint, gerty.mempool_endpoint,
), ),
) )
@ -129,7 +129,7 @@ async def get_mempool_info(endPoint: str, gerty) -> dict:
"UPDATE gerty.mempool SET data = ?, time = ? WHERE endpoint = ? AND mempool_endpoint = ?", "UPDATE gerty.mempool SET data = ?, time = ? WHERE endpoint = ? AND mempool_endpoint = ?",
( (
json.dumps(response.json()), json.dumps(response.json()),
int(time.time()), time.time(),
endPoint, endPoint,
gerty.mempool_endpoint, gerty.mempool_endpoint,
), ),

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -1,4 +1,5 @@
from fastapi import APIRouter from fastapi import APIRouter
from fastapi.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -12,4 +13,12 @@ def hivemind_renderer():
return template_renderer(["lnbits/extensions/hivemind/templates"]) return template_renderer(["lnbits/extensions/hivemind/templates"])
hivemind_static_files = [
{
"path": "/hivemind/static",
"app": StaticFiles(packages=[("lnbits", "extensions/hivemind/static")]),
"name": "hivemind_static",
}
]
from .views import * # noqa from .views import * # noqa

View File

@ -1,6 +1,6 @@
{ {
"name": "Hivemind", "name": "Hivemind",
"short_description": "Make cheap talk expensive!", "short_description": "Make cheap talk expensive!",
"icon": "batch_prediction", "tile": "/hivemind/static/image/hivemind.png",
"contributors": ["fiatjaf"] "contributors": ["fiatjaf"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "Invoices", "name": "Invoices",
"short_description": "Create invoices for your clients.", "short_description": "Create invoices for your clients.",
"icon": "request_quote", "tile": "/invoices/static/image/invoices.png",
"contributors": ["leesalminen"] "contributors": ["leesalminen"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -1,6 +1,6 @@
{ {
"name": "Spotify Jukebox", "name": "Spotify Jukebox",
"short_description": "Spotify jukebox middleware", "short_description": "Spotify jukebox middleware",
"icon": "radio", "tile": "/jukebox/static/image/jukebox.png",
"contributors": ["benarc"] "contributors": ["benarc"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,7 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
@ -17,9 +16,7 @@ templates = Jinja2Templates(directory="templates")
@jukebox_ext.get("/", response_class=HTMLResponse) @jukebox_ext.get("/", response_class=HTMLResponse)
async def index( async def index(request: Request, user: User = Depends(check_user_exists)):
request: Request, user: User = Depends(check_user_exists) # type: ignore
):
return jukebox_renderer().TemplateResponse( return jukebox_renderer().TemplateResponse(
"jukebox/index.html", {"request": request, "user": user.dict()} "jukebox/index.html", {"request": request, "user": user.dict()}
) )

View File

@ -3,10 +3,9 @@ import json
from http import HTTPStatus from http import HTTPStatus
import httpx import httpx
from fastapi.param_functions import Query from fastapi import Depends, Query
from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse # type: ignore from starlette.responses import HTMLResponse
from lnbits.core.services import create_invoice from lnbits.core.services import create_invoice
from lnbits.core.views.api import api_payment from lnbits.core.views.api import api_payment
@ -28,7 +27,7 @@ from .models import CreateJukeboxPayment, CreateJukeLinkData
@jukebox_ext.get("/api/v1/jukebox") @jukebox_ext.get("/api/v1/jukebox")
async def api_get_jukeboxs( async def api_get_jukeboxs(
wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore wallet: WalletTypeInfo = Depends(require_admin_key),
): ):
wallet_user = wallet.wallet.user wallet_user = wallet.wallet.user

View File

@ -1,7 +1,7 @@
{ {
"name": "DJ Livestream", "name": "DJ Livestream",
"short_description": "Sell tracks and split revenue (lnurl-pay)", "short_description": "Sell tracks and split revenue (lnurl-pay)",
"icon": "speaker", "tile": "/livestream/static/image/livestream.png",
"contributors": [ "contributors": [
"fiatjaf", "fiatjaf",
"cryptograffiti" "cryptograffiti"

View File

@ -90,7 +90,7 @@ async def lnurl_callback(
wallet_id=ls.wallet, wallet_id=ls.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo=await track.fullname(), memo=await track.fullname(),
unhashed_description=(await track.lnurlpay_metadata()).encode("utf-8"), unhashed_description=(await track.lnurlpay_metadata()).encode(),
extra={"tag": "livestream", "track": track.id, "comment": comment}, extra={"tag": "livestream", "track": track.id, "comment": comment},
) )

View File

@ -1,12 +1,12 @@
import json import json
from typing import Optional from typing import Optional
from fastapi.params import Query from fastapi import Query
from lnurl import Lnurl from lnurl import Lnurl
from lnurl import encode as lnurl_encode # type: ignore from lnurl import encode as lnurl_encode # type: ignore
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic.main import BaseModel from pydantic import BaseModel
from starlette.requests import Request from starlette.requests import Request

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -10,6 +11,14 @@ db = Database("ext_lnaddress")
lnaddress_ext: APIRouter = APIRouter(prefix="/lnaddress", tags=["lnaddress"]) lnaddress_ext: APIRouter = APIRouter(prefix="/lnaddress", tags=["lnaddress"])
lnaddress_static_files = [
{
"path": "/lnaddress/static",
"app": StaticFiles(directory="lnbits/extensions/lnaddress/static"),
"name": "lnaddress_static",
}
]
def lnaddress_renderer(): def lnaddress_renderer():
return template_renderer(["lnbits/extensions/lnaddress/templates"]) return template_renderer(["lnbits/extensions/lnaddress/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "Lightning Address", "name": "Lightning Address",
"short_description": "Sell LN addresses for your domain", "short_description": "Sell LN addresses for your domain",
"icon": "alternate_email", "tile": "/lnaddress/static/image/lnaddress.png",
"contributors": ["talvasconcelos"] "contributors": ["talvasconcelos"]
} }

View File

@ -72,7 +72,7 @@ async def lnurl_callback(address_id, amount: int = Query(...)):
"amount": int(amount_received / 1000), "amount": int(amount_received / 1000),
"description_hash": ( "description_hash": (
await address.lnurlpay_metadata(domain=domain.domain) await address.lnurlpay_metadata(domain=domain.domain)
).encode("utf-8"), ).encode(),
"extra": {"tag": f"Payment to {address.username}@{domain.domain}"}, "extra": {"tag": f"Payment to {address.username}@{domain.domain}"},
}, },
timeout=40, timeout=40,

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,4 +1,5 @@
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -7,6 +8,14 @@ db = Database("ext_lndhub")
lndhub_ext: APIRouter = APIRouter(prefix="/lndhub", tags=["lndhub"]) lndhub_ext: APIRouter = APIRouter(prefix="/lndhub", tags=["lndhub"])
lndhub_static_files = [
{
"path": "/lndhub/static",
"app": StaticFiles(directory="lnbits/extensions/lndhub/static"),
"name": "lndhub_static",
}
]
def lndhub_renderer(): def lndhub_renderer():
return template_renderer(["lnbits/extensions/lndhub/templates"]) return template_renderer(["lnbits/extensions/lndhub/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "LndHub", "name": "LndHub",
"short_description": "Access lnbits from BlueWallet or Zeus", "short_description": "Access lnbits from BlueWallet or Zeus",
"icon": "navigation", "tile": "/lndhub/static/image/lndhub.png",
"contributors": ["fiatjaf"] "contributors": ["fiatjaf"]
} }

View File

@ -23,7 +23,7 @@ async def check_wallet(
) )
t = api_key_header_auth.split(" ")[1] t = api_key_header_auth.split(" ")[1]
_, token = b64decode(t).decode("utf-8").split(":") _, token = b64decode(t).decode().split(":")
return await get_key_type(r, api_key_header=token) return await get_key_type(r, api_key_header=token)

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -35,9 +35,9 @@ async def lndhub_auth(data: AuthData):
token = ( token = (
data.refresh_token data.refresh_token
if data.refresh_token if data.refresh_token
else urlsafe_b64encode( else urlsafe_b64encode((data.login + ":" + data.password).encode()).decode(
(data.login + ":" + data.password).encode("utf-8") "ascii"
).decode("ascii") )
) )
return {"refresh_token": token, "access_token": token} return {"refresh_token": token, "access_token": token}

View File

@ -2,6 +2,7 @@ import asyncio
import json import json
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -11,6 +12,14 @@ db = Database("ext_lnticket")
lnticket_ext: APIRouter = APIRouter(prefix="/lnticket", tags=["LNTicket"]) lnticket_ext: APIRouter = APIRouter(prefix="/lnticket", tags=["LNTicket"])
lnticket_static_files = [
{
"path": "/lnticket/static",
"app": StaticFiles(directory="lnbits/extensions/lnticket/static"),
"name": "lnticket_static",
}
]
def lnticket_renderer(): def lnticket_renderer():
return template_renderer(["lnbits/extensions/lnticket/templates"]) return template_renderer(["lnbits/extensions/lnticket/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "Support Tickets", "name": "Support Tickets",
"short_description": "LN support ticket system", "short_description": "LN support ticket system",
"icon": "contact_support", "tile": "/lnticket/static/image/lntickets.png",
"contributors": ["benarc"] "contributors": ["benarc"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -19,7 +19,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if payment.extra.get("tag") != "lnticket": if not payment.extra or payment.extra.get("tag") != "lnticket":
# not a lnticket invoice # not a lnticket invoice
return return

View File

@ -33,6 +33,7 @@ async def display(request: Request, form_id):
) )
wallet = await get_wallet(form.wallet) wallet = await get_wallet(form.wallet)
assert wallet
return lnticket_renderer().TemplateResponse( return lnticket_renderer().TemplateResponse(
"lnticket/display.html", "lnticket/display.html",

View File

@ -1,8 +1,7 @@
import re import re
from http import HTTPStatus from http import HTTPStatus
from fastapi import Query from fastapi import Depends, Query
from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user from lnbits.core.crud import get_user
@ -35,7 +34,8 @@ async def api_forms_get(
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [form.dict() for form in await get_forms(wallet_ids)] return [form.dict() for form in await get_forms(wallet_ids)]
@ -91,7 +91,8 @@ async def api_tickets(
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [form.dict() for form in await get_tickets(wallet_ids)] return [form.dict() for form in await get_tickets(wallet_ids)]

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -10,6 +11,14 @@ db = Database("ext_lnurldevice")
lnurldevice_ext: APIRouter = APIRouter(prefix="/lnurldevice", tags=["lnurldevice"]) lnurldevice_ext: APIRouter = APIRouter(prefix="/lnurldevice", tags=["lnurldevice"])
lnurldevice_static_files = [
{
"path": "/lnurldevice/static",
"app": StaticFiles(directory="lnbits/extensions/lnurldevice/static"),
"name": "lnurldevice_static",
}
]
def lnurldevice_renderer(): def lnurldevice_renderer():
return template_renderer(["lnbits/extensions/lnurldevice/templates"]) return template_renderer(["lnbits/extensions/lnurldevice/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "LNURLDevice", "name": "LNURLDevice",
"short_description": "For offline LNURL devices", "short_description": "For offline LNURL devices",
"icon": "point_of_sale", "tile": "/lnurldevice/static/image/lnurldevice.png",
"contributors": ["arcbtc"] "contributors": ["arcbtc"]
} }

View File

@ -246,7 +246,7 @@ async def lnurl_callback(
wallet_id=device.wallet, wallet_id=device.wallet,
amount=int(lnurldevicepayment.sats / 1000), amount=int(lnurldevicepayment.sats / 1000),
memo=device.id + " PIN " + str(lnurldevicepayment.pin), memo=device.id + " PIN " + str(lnurldevicepayment.pin),
unhashed_description=device.lnurlpay_metadata.encode("utf-8"), unhashed_description=device.lnurlpay_metadata.encode(),
extra={ extra={
"tag": "Switch", "tag": "Switch",
"pin": str(lnurldevicepayment.pin), "pin": str(lnurldevicepayment.pin),
@ -267,7 +267,7 @@ async def lnurl_callback(
wallet_id=device.wallet, wallet_id=device.wallet,
amount=int(lnurldevicepayment.sats / 1000), amount=int(lnurldevicepayment.sats / 1000),
memo=device.title, memo=device.title,
unhashed_description=device.lnurlpay_metadata.encode("utf-8"), unhashed_description=device.lnurlpay_metadata.encode(),
extra={"tag": "PoS"}, extra={"tag": "PoS"},
) )
lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment = await update_lnurldevicepayment(

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,7 +1,7 @@
{ {
"name": "LNURLp", "name": "LNURLp",
"short_description": "Make reusable LNURL pay links", "short_description": "Make reusable LNURL pay links",
"icon": "receipt", "tile": "/lnurlp/static/image/lnurl-pay.png",
"contributors": [ "contributors": [
"arcbtc", "arcbtc",
"eillarra", "eillarra",

View File

@ -1,18 +1,19 @@
from typing import List, Optional, Union from typing import List, Optional, Union
from lnbits.helpers import urlsafe_short_hash from lnbits.db import SQLITE
from . import db from . import db
from .models import CreatePayLinkData, PayLink from .models import CreatePayLinkData, PayLink
async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
link_id = urlsafe_short_hash()
result = await db.execute( returning = "" if db.type == SQLITE else "RETURNING ID"
method = db.execute if db.type == SQLITE else db.fetchone
result = await (method)(
f""" f"""
INSERT INTO lnurlp.pay_links ( INSERT INTO lnurlp.pay_links (
id,
wallet, wallet,
description, description,
min, min,
@ -28,11 +29,10 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
currency, currency,
fiat_base_multiplier fiat_base_multiplier
) )
VALUES (?, ?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, 0, 0, ?, ?, ?, ?, ?, ?, ?, ?)
{returning} {returning}
""", """,
( (
link_id,
wallet_id, wallet_id,
data.description, data.description,
data.min, data.min,
@ -47,6 +47,10 @@ async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
data.fiat_base_multiplier, data.fiat_base_multiplier,
), ),
) )
if db.type == SQLITE:
link_id = result._result_proxy.lastrowid
else:
link_id = result[0]
link = await get_pay_link(link_id) link = await get_pay_link(link_id)
assert link, "Newly created link couldn't be retrieved" assert link, "Newly created link couldn't be retrieved"

View File

@ -87,7 +87,7 @@ async def api_lnurl_callback(request: Request, link_id):
wallet_id=link.wallet, wallet_id=link.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo=link.description, memo=link.description,
unhashed_description=link.lnurlpay_metadata.encode("utf-8"), unhashed_description=link.lnurlpay_metadata.encode(),
extra={ extra={
"tag": "lnurlp", "tag": "lnurlp",
"link": link.id, "link": link.id,

View File

@ -68,76 +68,3 @@ async def m005_webhook_headers_and_body(db):
""" """
await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_headers TEXT;") await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_headers TEXT;")
await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_body TEXT;") await db.execute("ALTER TABLE lnurlp.pay_links ADD COLUMN webhook_body TEXT;")
async def m006_redux(db):
"""
Add UUID ID's to links and migrates existing data
"""
await db.execute("ALTER TABLE lnurlp.pay_links RENAME TO pay_links_old")
await db.execute(
f"""
CREATE TABLE lnurlp.pay_links (
id TEXT PRIMARY KEY,
wallet TEXT NOT NULL,
description TEXT NOT NULL,
min INTEGER NOT NULL,
max INTEGER,
currency TEXT,
fiat_base_multiplier INTEGER DEFAULT 1,
served_meta INTEGER NOT NULL,
served_pr INTEGER NOT NULL,
webhook_url TEXT,
success_text TEXT,
success_url TEXT,
comment_chars INTEGER DEFAULT 0,
webhook_headers TEXT,
webhook_body TEXT
);
"""
)
for row in [
list(row) for row in await db.fetchall("SELECT * FROM lnurlp.pay_links_old")
]:
await db.execute(
"""
INSERT INTO lnurlp.pay_links (
id,
wallet,
description,
min,
served_meta,
served_pr,
webhook_url,
success_text,
success_url,
currency,
comment_chars,
max,
fiat_base_multiplier,
webhook_headers,
webhook_body
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
row[0],
row[1],
row[2],
row[3],
row[4],
row[5],
row[6],
row[7],
row[8],
row[9],
row[10],
row[11],
row[12],
row[13],
row[14],
),
)
await db.execute("DROP TABLE lnurlp.pay_links_old")

View File

@ -26,7 +26,7 @@ class CreatePayLinkData(BaseModel):
class PayLink(BaseModel): class PayLink(BaseModel):
id: str id: int
wallet: str wallet: str
description: str description: str
min: float min: float

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,8 +1,7 @@
# type: ignore # type: ignore
from os import getenv from os import getenv
from fastapi import Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from pyngrok import conf, ngrok from pyngrok import conf, ngrok
@ -35,9 +34,7 @@ ngrok_tunnel = ngrok.connect(port)
@ngrok_ext.get("/") @ngrok_ext.get("/")
async def index( async def index(request: Request, user: User = Depends(check_user_exists)):
request: Request, user: User = Depends(check_user_exists) # type: ignore
):
return ngrok_renderer().TemplateResponse( return ngrok_renderer().TemplateResponse(
"ngrok/index.html", {"request": request, "ngrok": string5, "user": user.dict()} "ngrok/index.html", {"request": request, "ngrok": string5, "user": user.dict()}
) )

View File

@ -1,6 +1,6 @@
{ {
"name": "Nostr NIP-5", "name": "Nostr NIP-5",
"short_description": "Verify addresses for Nostr NIP-5", "short_description": "Verify addresses for Nostr NIP-5",
"icon": "request_quote", "tile": "/nostrnip5/static/image/nostrnip5.png",
"contributors": ["leesalminen"] "contributors": ["leesalminen"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -1,7 +1,7 @@
{ {
"name": "OfflineShop", "name": "OfflineShop",
"short_description": "Receive payments for products offline!", "short_description": "Receive payments for products offline!",
"icon": "nature_people", "tile": "/offlineshop/static/image/offlineshop.png",
"contributors": [ "contributors": [
"fiatjaf" "fiatjaf"
] ]

View File

@ -73,7 +73,7 @@ async def lnurl_callback(request: Request, item_id: int):
wallet_id=shop.wallet, wallet_id=shop.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo=item.name, memo=item.name,
unhashed_description=(await item.lnurlpay_metadata()).encode("utf-8"), unhashed_description=(await item.lnurlpay_metadata()).encode(),
extra={"tag": "offlineshop", "item": item.id}, extra={"tag": "offlineshop", "item": item.id},
) )
except Exception as exc: except Exception as exc:

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,4 +1,5 @@
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -7,6 +8,14 @@ db = Database("ext_paywall")
paywall_ext: APIRouter = APIRouter(prefix="/paywall", tags=["Paywall"]) paywall_ext: APIRouter = APIRouter(prefix="/paywall", tags=["Paywall"])
paywall_static_files = [
{
"path": "/paywall/static",
"app": StaticFiles(directory="lnbits/extensions/paywall/static"),
"name": "paywall_static",
}
]
def paywall_renderer(): def paywall_renderer():
return template_renderer(["lnbits/extensions/paywall/templates"]) return template_renderer(["lnbits/extensions/paywall/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "Paywall", "name": "Paywall",
"short_description": "Create paywalls for content", "short_description": "Create paywalls for content",
"icon": "policy", "tile": "/paywall/static/image/paywall.png",
"contributors": ["eillarra"] "contributors": ["eillarra"]
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -19,7 +19,8 @@ async def api_paywalls(
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [paywall.dict() for paywall in await get_paywalls(wallet_ids)] return [paywall.dict() for paywall in await get_paywalls(wallet_ids)]
@ -57,6 +58,7 @@ async def api_paywall_create_invoice(
data: CreatePaywallInvoice, paywall_id: str = Query(None) data: CreatePaywallInvoice, paywall_id: str = Query(None)
): ):
paywall = await get_paywall(paywall_id) paywall = await get_paywall(paywall_id)
assert paywall
if data.amount < paywall.amount: if data.amount < paywall.amount:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, status_code=HTTPStatus.BAD_REQUEST,
@ -94,7 +96,9 @@ async def api_paywal_check_invoice(
if is_paid: if is_paid:
wallet = await get_wallet(paywall.wallet) wallet = await get_wallet(paywall.wallet)
assert wallet
payment = await wallet.get_payment(payment_hash) payment = await wallet.get_payment(payment_hash)
assert payment
await payment.set_pending(False) await payment.set_pending(False)
return {"paid": True, "url": paywall.url, "remembers": paywall.remembers} return {"paid": True, "url": paywall.url, "remembers": paywall.remembers}

View File

@ -1,4 +1,5 @@
from fastapi import APIRouter from fastapi import APIRouter
from starlette.staticfiles import StaticFiles
from lnbits.db import Database from lnbits.db import Database
from lnbits.helpers import template_renderer from lnbits.helpers import template_renderer
@ -7,6 +8,14 @@ db = Database("ext_satsdice")
satsdice_ext: APIRouter = APIRouter(prefix="/satsdice", tags=["satsdice"]) satsdice_ext: APIRouter = APIRouter(prefix="/satsdice", tags=["satsdice"])
satsdice_static_files = [
{
"path": "/satsdice/static",
"app": StaticFiles(directory="lnbits/extensions/satsdice/static"),
"name": "satsdice_static",
}
]
def satsdice_renderer(): def satsdice_renderer():
return template_renderer(["lnbits/extensions/satsdice/templates"]) return template_renderer(["lnbits/extensions/satsdice/templates"])

View File

@ -1,6 +1,6 @@
{ {
"name": "Sats Dice", "name": "Sats Dice",
"short_description": "LNURL Satoshi dice", "short_description": "LNURL Satoshi dice",
"icon": "casino", "tile": "/satsdice/static/image/satsdice.png",
"contributors": ["arcbtc"] "contributors": ["arcbtc"]
} }

View File

@ -76,7 +76,7 @@ async def api_lnurlp_callback(
wallet_id=link.wallet, wallet_id=link.wallet,
amount=int(amount_received / 1000), amount=int(amount_received / 1000),
memo="Satsdice bet", memo="Satsdice bet",
unhashed_description=link.lnurlpay_metadata.encode("utf-8"), unhashed_description=link.lnurlpay_metadata.encode(),
extra={"tag": "satsdice", "link": link.id, "comment": "comment"}, extra={"tag": "satsdice", "link": link.id, "comment": "comment"},
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -3,9 +3,7 @@ from http import HTTPStatus
from io import BytesIO from io import BytesIO
import pyqrcode import pyqrcode
from fastapi import Request from fastapi import Depends, Query, Request
from fastapi.param_functions import Query
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
@ -28,9 +26,7 @@ templates = Jinja2Templates(directory="templates")
@satsdice_ext.get("/", response_class=HTMLResponse) @satsdice_ext.get("/", response_class=HTMLResponse)
async def index( async def index(request: Request, user: User = Depends(check_user_exists)):
request: Request, user: User = Depends(check_user_exists) # type: ignore
):
return satsdice_renderer().TemplateResponse( return satsdice_renderer().TemplateResponse(
"satsdice/index.html", {"request": request, "user": user.dict()} "satsdice/index.html", {"request": request, "user": user.dict()}
) )
@ -108,7 +104,7 @@ async def displaywin(
data = CreateSatsDiceWithdraw( data = CreateSatsDiceWithdraw(
satsdice_pay=satsdicelink.id, satsdice_pay=satsdicelink.id,
value=paylink.value * satsdicelink.multiplier, value=int(paylink.value * satsdicelink.multiplier),
payment_hash=payment_hash, payment_hash=payment_hash,
used=0, used=0,
) )

View File

@ -1,8 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, Query, Request
from fastapi.param_functions import Query
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
@ -26,7 +24,7 @@ from .models import CreateSatsDiceLink
@satsdice_ext.get("/api/v1/links") @satsdice_ext.get("/api/v1/links")
async def api_links( async def api_links(
request: Request, request: Request,
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
all_wallets: bool = Query(False), all_wallets: bool = Query(False),
): ):
wallet_ids = [wallet.wallet.id] wallet_ids = [wallet.wallet.id]
@ -49,7 +47,7 @@ async def api_links(
@satsdice_ext.get("/api/v1/links/{link_id}") @satsdice_ext.get("/api/v1/links/{link_id}")
async def api_link_retrieve( async def api_link_retrieve(
link_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore link_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type)
): ):
link = await get_satsdice_pay(link_id) link = await get_satsdice_pay(link_id)
@ -70,7 +68,7 @@ async def api_link_retrieve(
@satsdice_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) @satsdice_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
async def api_link_create_or_update( async def api_link_create_or_update(
data: CreateSatsDiceLink, data: CreateSatsDiceLink,
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
link_id: str = Query(None), link_id: str = Query(None),
): ):
if data.min_bet > data.max_bet: if data.min_bet > data.max_bet:
@ -98,7 +96,7 @@ async def api_link_create_or_update(
@satsdice_ext.delete("/api/v1/links/{link_id}") @satsdice_ext.delete("/api/v1/links/{link_id}")
async def api_link_delete( async def api_link_delete(
wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore wallet: WalletTypeInfo = Depends(get_key_type),
link_id: str = Query(None), link_id: str = Query(None),
): ):
link = await get_satsdice_pay(link_id) link = await get_satsdice_pay(link_id)

Some files were not shown because too many files have changed in this diff Show More