chore: update python packages + formatting + cleanup (#3221)
This commit is contained in:
parent
c4c03d96a3
commit
a16078a6ba
53 changed files with 1159 additions and 576 deletions
|
|
@ -9,16 +9,13 @@ from .decorators import (
|
||||||
from .exceptions import InvoiceError, PaymentError
|
from .exceptions import InvoiceError, PaymentError
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# decorators
|
"InvoiceError",
|
||||||
"require_admin_key",
|
"PaymentError",
|
||||||
"require_invoice_key",
|
|
||||||
"check_admin",
|
"check_admin",
|
||||||
"check_super_user",
|
"check_super_user",
|
||||||
"check_user_exists",
|
"check_user_exists",
|
||||||
# services
|
|
||||||
"pay_invoice",
|
|
||||||
"create_invoice",
|
"create_invoice",
|
||||||
# exceptions
|
"pay_invoice",
|
||||||
"PaymentError",
|
"require_admin_key",
|
||||||
"InvoiceError",
|
"require_invoice_key",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,6 @@ from .middleware import (
|
||||||
add_ip_block_middleware,
|
add_ip_block_middleware,
|
||||||
add_ratelimit_middleware,
|
add_ratelimit_middleware,
|
||||||
)
|
)
|
||||||
from .requestvars import g
|
|
||||||
from .tasks import (
|
from .tasks import (
|
||||||
check_pending_payments,
|
check_pending_payments,
|
||||||
internal_invoice_listener,
|
internal_invoice_listener,
|
||||||
|
|
@ -171,8 +170,6 @@ def create_app() -> FastAPI:
|
||||||
name="library",
|
name="library",
|
||||||
)
|
)
|
||||||
|
|
||||||
g().base_url = f"http://{settings.host}:{settings.port}"
|
|
||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
|
CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -85,87 +85,78 @@ from .webpush import (
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# audit
|
|
||||||
"create_audit_entry",
|
|
||||||
# db_versions
|
|
||||||
"get_db_version",
|
|
||||||
"get_db_versions",
|
|
||||||
"update_migration_version",
|
|
||||||
"delete_dbversion",
|
|
||||||
# extensions
|
|
||||||
"create_installed_extension",
|
|
||||||
"create_user_extension",
|
|
||||||
"delete_installed_extension",
|
|
||||||
"drop_extension_db",
|
|
||||||
"get_installed_extension",
|
|
||||||
"get_installed_extensions",
|
|
||||||
"get_user_active_extensions_ids",
|
|
||||||
"get_user_extension",
|
|
||||||
"update_installed_extension",
|
|
||||||
"update_installed_extension_state",
|
|
||||||
"update_user_extension",
|
|
||||||
"get_user_extensions",
|
|
||||||
# payments
|
|
||||||
"DateTrunc",
|
"DateTrunc",
|
||||||
"check_internal",
|
"check_internal",
|
||||||
"create_payment",
|
|
||||||
"delete_expired_invoices",
|
|
||||||
"delete_wallet_payment",
|
|
||||||
"get_latest_payments_by_extension",
|
|
||||||
"get_payment",
|
|
||||||
"get_payments",
|
|
||||||
"get_payments_history",
|
|
||||||
"get_payments_paginated",
|
|
||||||
"get_standalone_payment",
|
|
||||||
"get_wallet_payment",
|
|
||||||
"is_internal_status_success",
|
|
||||||
"mark_webhook_sent",
|
|
||||||
"update_payment",
|
|
||||||
"update_payment_checking_id",
|
|
||||||
"update_payment_extra",
|
|
||||||
# settings
|
|
||||||
"create_admin_settings",
|
|
||||||
"delete_admin_settings",
|
|
||||||
"get_admin_settings",
|
|
||||||
"get_super_settings",
|
|
||||||
"update_admin_settings",
|
|
||||||
"update_super_user",
|
|
||||||
"reset_core_settings",
|
|
||||||
# tinyurl
|
|
||||||
"create_tinyurl",
|
|
||||||
"delete_tinyurl",
|
|
||||||
"get_tinyurl",
|
|
||||||
"get_tinyurl_by_url",
|
|
||||||
# users
|
|
||||||
"create_account",
|
"create_account",
|
||||||
|
"create_admin_settings",
|
||||||
|
"create_audit_entry",
|
||||||
|
"create_installed_extension",
|
||||||
|
"create_payment",
|
||||||
|
"create_tinyurl",
|
||||||
|
"create_user_extension",
|
||||||
|
"create_wallet",
|
||||||
|
"create_webpush_subscription",
|
||||||
"delete_account",
|
"delete_account",
|
||||||
"delete_accounts_no_wallets",
|
"delete_accounts_no_wallets",
|
||||||
|
"delete_admin_settings",
|
||||||
|
"delete_dbversion",
|
||||||
|
"delete_expired_invoices",
|
||||||
|
"delete_installed_extension",
|
||||||
|
"delete_tinyurl",
|
||||||
|
"delete_unused_wallets",
|
||||||
|
"delete_wallet",
|
||||||
|
"delete_wallet_by_id",
|
||||||
|
"delete_wallet_payment",
|
||||||
|
"delete_webpush_subscription",
|
||||||
|
"delete_webpush_subscriptions",
|
||||||
|
"drop_extension_db",
|
||||||
|
"force_delete_wallet",
|
||||||
"get_account",
|
"get_account",
|
||||||
"get_account_by_email",
|
"get_account_by_email",
|
||||||
"get_account_by_pubkey",
|
"get_account_by_pubkey",
|
||||||
"get_account_by_username",
|
"get_account_by_username",
|
||||||
"get_account_by_username_or_email",
|
"get_account_by_username_or_email",
|
||||||
"get_accounts",
|
"get_accounts",
|
||||||
"get_user",
|
"get_admin_settings",
|
||||||
"get_user_from_account",
|
"get_db_version",
|
||||||
"get_user_access_control_lists",
|
"get_db_versions",
|
||||||
"update_account",
|
"get_installed_extension",
|
||||||
# wallets
|
"get_installed_extensions",
|
||||||
"create_wallet",
|
"get_latest_payments_by_extension",
|
||||||
"delete_unused_wallets",
|
"get_payment",
|
||||||
"delete_wallet",
|
"get_payments",
|
||||||
"delete_wallet_by_id",
|
"get_payments_history",
|
||||||
"force_delete_wallet",
|
"get_payments_paginated",
|
||||||
|
"get_standalone_payment",
|
||||||
|
"get_super_settings",
|
||||||
|
"get_tinyurl",
|
||||||
|
"get_tinyurl_by_url",
|
||||||
"get_total_balance",
|
"get_total_balance",
|
||||||
|
"get_user",
|
||||||
|
"get_user_access_control_lists",
|
||||||
|
"get_user_active_extensions_ids",
|
||||||
|
"get_user_extension",
|
||||||
|
"get_user_extensions",
|
||||||
|
"get_user_from_account",
|
||||||
"get_wallet",
|
"get_wallet",
|
||||||
"get_wallet_for_key",
|
"get_wallet_for_key",
|
||||||
|
"get_wallet_payment",
|
||||||
"get_wallets",
|
"get_wallets",
|
||||||
"remove_deleted_wallets",
|
|
||||||
"update_wallet",
|
|
||||||
# webpush
|
|
||||||
"create_webpush_subscription",
|
|
||||||
"delete_webpush_subscription",
|
|
||||||
"delete_webpush_subscriptions",
|
|
||||||
"get_webpush_subscription",
|
"get_webpush_subscription",
|
||||||
"get_webpush_subscriptions_for_user",
|
"get_webpush_subscriptions_for_user",
|
||||||
|
"is_internal_status_success",
|
||||||
|
"mark_webhook_sent",
|
||||||
|
"remove_deleted_wallets",
|
||||||
|
"reset_core_settings",
|
||||||
|
"update_account",
|
||||||
|
"update_admin_settings",
|
||||||
|
"update_installed_extension",
|
||||||
|
"update_installed_extension_state",
|
||||||
|
"update_migration_version",
|
||||||
|
"update_payment",
|
||||||
|
"update_payment_checking_id",
|
||||||
|
"update_payment_extra",
|
||||||
|
"update_super_user",
|
||||||
|
"update_user_extension",
|
||||||
|
"update_wallet",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Any, Optional, Tuple
|
from typing import Any, Optional
|
||||||
|
|
||||||
from lnbits.core.crud.wallets import get_total_balance, get_wallet, get_wallets_ids
|
from lnbits.core.crud.wallets import get_total_balance, get_wallet, get_wallets_ids
|
||||||
from lnbits.core.db import db
|
from lnbits.core.db import db
|
||||||
|
|
@ -394,7 +394,7 @@ async def get_daily_stats(
|
||||||
filters: Optional[Filters[PaymentFilters]] = None,
|
filters: Optional[Filters[PaymentFilters]] = None,
|
||||||
user_id: Optional[str] = None,
|
user_id: Optional[str] = None,
|
||||||
conn: Optional[Connection] = None,
|
conn: Optional[Connection] = None,
|
||||||
) -> Tuple[list[PaymentDailyStats], list[PaymentDailyStats]]:
|
) -> tuple[list[PaymentDailyStats], list[PaymentDailyStats]]:
|
||||||
|
|
||||||
if not filters:
|
if not filters:
|
||||||
filters = Filters()
|
filters = Filters()
|
||||||
|
|
|
||||||
|
|
@ -48,62 +48,54 @@ from .wallets import BaseWallet, CreateWallet, KeyType, Wallet, WalletTypeInfo
|
||||||
from .webpush import CreateWebPushSubscription, WebPushSubscription
|
from .webpush import CreateWebPushSubscription, WebPushSubscription
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# audit
|
|
||||||
"AuditEntry",
|
|
||||||
"AuditFilters",
|
|
||||||
# lnurl
|
|
||||||
"CreateLnurl",
|
|
||||||
"CreateLnurlAuth",
|
|
||||||
"PayLnurlWData",
|
|
||||||
# misc
|
|
||||||
"BalanceDelta",
|
|
||||||
"Callback",
|
|
||||||
"ConversionData",
|
|
||||||
"CoreAppExtra",
|
|
||||||
"DbVersion",
|
|
||||||
"SimpleStatus",
|
|
||||||
# payments
|
|
||||||
"CreateInvoice",
|
|
||||||
"CreatePayment",
|
|
||||||
"DecodePayment",
|
|
||||||
"PayInvoice",
|
|
||||||
"Payment",
|
|
||||||
"PaymentCountField",
|
|
||||||
"PaymentCountStat",
|
|
||||||
"PaymentDailyStats",
|
|
||||||
"PaymentsStatusCount",
|
|
||||||
"PaymentWalletStats",
|
|
||||||
"PaymentExtra",
|
|
||||||
"PaymentFilters",
|
|
||||||
"PaymentHistoryPoint",
|
|
||||||
"PaymentState",
|
|
||||||
# tinyurl
|
|
||||||
"TinyURL",
|
|
||||||
# users
|
|
||||||
"AccessTokenPayload",
|
"AccessTokenPayload",
|
||||||
"Account",
|
"Account",
|
||||||
"AccountFilters",
|
"AccountFilters",
|
||||||
"AccountOverview",
|
"AccountOverview",
|
||||||
"UserAcls",
|
"AuditEntry",
|
||||||
|
"AuditFilters",
|
||||||
|
"BalanceDelta",
|
||||||
|
"BaseWallet",
|
||||||
|
"Callback",
|
||||||
|
"ConversionData",
|
||||||
|
"CoreAppExtra",
|
||||||
|
"CreateInvoice",
|
||||||
|
"CreateLnurl",
|
||||||
|
"CreateLnurlAuth",
|
||||||
|
"CreatePayment",
|
||||||
"CreateUser",
|
"CreateUser",
|
||||||
"RegisterUser",
|
"CreateWallet",
|
||||||
|
"CreateWebPushSubscription",
|
||||||
|
"DbVersion",
|
||||||
|
"DecodePayment",
|
||||||
|
"KeyType",
|
||||||
"LoginUsernamePassword",
|
"LoginUsernamePassword",
|
||||||
"LoginUsr",
|
"LoginUsr",
|
||||||
|
"PayInvoice",
|
||||||
|
"PayLnurlWData",
|
||||||
|
"Payment",
|
||||||
|
"PaymentCountField",
|
||||||
|
"PaymentCountStat",
|
||||||
|
"PaymentDailyStats",
|
||||||
|
"PaymentExtra",
|
||||||
|
"PaymentFilters",
|
||||||
|
"PaymentHistoryPoint",
|
||||||
|
"PaymentState",
|
||||||
|
"PaymentWalletStats",
|
||||||
|
"PaymentsStatusCount",
|
||||||
|
"RegisterUser",
|
||||||
"ResetUserPassword",
|
"ResetUserPassword",
|
||||||
|
"SimpleStatus",
|
||||||
|
"TinyURL",
|
||||||
"UpdateBalance",
|
"UpdateBalance",
|
||||||
"UpdateSuperuserPassword",
|
"UpdateSuperuserPassword",
|
||||||
"UpdateUser",
|
"UpdateUser",
|
||||||
"UpdateUserPassword",
|
"UpdateUserPassword",
|
||||||
"UpdateUserPubkey",
|
"UpdateUserPubkey",
|
||||||
"User",
|
"User",
|
||||||
|
"UserAcls",
|
||||||
"UserExtra",
|
"UserExtra",
|
||||||
# wallets
|
|
||||||
"BaseWallet",
|
|
||||||
"CreateWallet",
|
|
||||||
"KeyType",
|
|
||||||
"Wallet",
|
"Wallet",
|
||||||
"WalletTypeInfo",
|
"WalletTypeInfo",
|
||||||
# webpush
|
|
||||||
"CreateWebPushSubscription",
|
|
||||||
"WebPushSubscription",
|
"WebPushSubscription",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
"""Keycloak SSO Login Helper
|
"""Keycloak SSO Login Helper"""
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,40 +34,33 @@ from .users import (
|
||||||
from .websockets import websocket_manager, websocket_updater
|
from .websockets import websocket_manager, websocket_updater
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# funding source
|
|
||||||
"get_balance_delta",
|
|
||||||
"switch_to_voidwallet",
|
|
||||||
# lnurl
|
|
||||||
"redeem_lnurl_withdraw",
|
|
||||||
"perform_lnurlauth",
|
|
||||||
# notifications
|
|
||||||
"enqueue_notification",
|
|
||||||
"send_payment_notification",
|
|
||||||
# payments
|
|
||||||
"calculate_fiat_amounts",
|
"calculate_fiat_amounts",
|
||||||
|
"check_admin_settings",
|
||||||
"check_transaction_status",
|
"check_transaction_status",
|
||||||
"check_wallet_limits",
|
"check_wallet_limits",
|
||||||
"create_invoice",
|
|
||||||
"create_wallet_invoice",
|
|
||||||
"create_fiat_invoice",
|
|
||||||
"fee_reserve",
|
|
||||||
"fee_reserve_total",
|
|
||||||
"get_payments_daily_stats",
|
|
||||||
"pay_invoice",
|
|
||||||
"service_fee",
|
|
||||||
"update_pending_payment",
|
|
||||||
"update_pending_payments",
|
|
||||||
"update_wallet_balance",
|
|
||||||
# settings
|
|
||||||
"check_webpush_settings",
|
"check_webpush_settings",
|
||||||
"update_cached_settings",
|
"create_fiat_invoice",
|
||||||
# users
|
"create_invoice",
|
||||||
"check_admin_settings",
|
|
||||||
"create_user_account",
|
"create_user_account",
|
||||||
"create_user_account_no_ckeck",
|
"create_user_account_no_ckeck",
|
||||||
|
"create_wallet_invoice",
|
||||||
|
"enqueue_notification",
|
||||||
|
"fee_reserve",
|
||||||
|
"fee_reserve_total",
|
||||||
|
"get_balance_delta",
|
||||||
|
"get_payments_daily_stats",
|
||||||
|
"pay_invoice",
|
||||||
|
"perform_lnurlauth",
|
||||||
|
"redeem_lnurl_withdraw",
|
||||||
|
"send_payment_notification",
|
||||||
|
"service_fee",
|
||||||
|
"switch_to_voidwallet",
|
||||||
|
"update_cached_settings",
|
||||||
|
"update_pending_payment",
|
||||||
|
"update_pending_payments",
|
||||||
"update_user_account",
|
"update_user_account",
|
||||||
"update_user_extensions",
|
"update_user_extensions",
|
||||||
# websockets
|
"update_wallet_balance",
|
||||||
"websocket_manager",
|
"websocket_manager",
|
||||||
"websocket_updater",
|
"websocket_updater",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -48,7 +47,7 @@ async def send_nostr_dm(
|
||||||
return dm_event.to_dict()
|
return dm_event.to_dict()
|
||||||
|
|
||||||
|
|
||||||
async def fetch_nip5_details(identifier: str) -> Tuple[str, list[str]]:
|
async def fetch_nip5_details(identifier: str) -> tuple[str, list[str]]:
|
||||||
identifier, domain = identifier.split("@")
|
identifier, domain = identifier.split("@")
|
||||||
if not identifier or not domain:
|
if not identifier or not domain:
|
||||||
raise ValueError("Invalid NIP5 identifier")
|
raise ValueError("Invalid NIP5 identifier")
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import smtplib
|
||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Optional, Tuple
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -186,7 +186,7 @@ def is_message_type_enabled(message_type: NotificationType) -> bool:
|
||||||
|
|
||||||
def _notification_message_to_text(
|
def _notification_message_to_text(
|
||||||
notification_message: NotificationMessage,
|
notification_message: NotificationMessage,
|
||||||
) -> Tuple[str, str]:
|
) -> tuple[str, str]:
|
||||||
message_type = notification_message.message_type.value
|
message_type = notification_message.message_type.value
|
||||||
meesage_value = NOTIFICATION_TEMPLATES.get(message_type, message_type)
|
meesage_value = NOTIFICATION_TEMPLATES.get(message_type, message_type)
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Callable, Coroutine
|
from collections.abc import Coroutine
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Annotated, List, Optional, Union
|
from typing import Annotated, Optional, Union
|
||||||
from urllib.parse import urlencode, urlparse
|
from urllib.parse import urlencode, urlparse
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
@ -70,7 +70,7 @@ async def robots():
|
||||||
|
|
||||||
@generic_router.get("/extensions", name="extensions", response_class=HTMLResponse)
|
@generic_router.get("/extensions", name="extensions", response_class=HTMLResponse)
|
||||||
async def extensions(request: Request, user: User = Depends(check_user_exists)):
|
async def extensions(request: Request, user: User = Depends(check_user_exists)):
|
||||||
installed_exts: List[InstallableExtension] = await get_installed_extensions()
|
installed_exts: list[InstallableExtension] = await get_installed_extensions()
|
||||||
installed_exts_ids = [e.id for e in installed_exts]
|
installed_exts_ids = [e.id for e in installed_exts]
|
||||||
|
|
||||||
installable_exts = await InstallableExtension.get_installable_extensions()
|
installable_exts = await InstallableExtension.get_installable_extensions()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from fastapi import APIRouter, Body, Depends, HTTPException
|
from fastapi import APIRouter, Body, Depends, HTTPException
|
||||||
|
|
@ -91,7 +91,7 @@ async def api_get_info(
|
||||||
@node_router.get("/channels")
|
@node_router.get("/channels")
|
||||||
async def api_get_channels(
|
async def api_get_channels(
|
||||||
node: Node = Depends(require_node),
|
node: Node = Depends(require_node),
|
||||||
) -> Optional[List[NodeChannel]]:
|
) -> Optional[list[NodeChannel]]:
|
||||||
return await node.get_channels()
|
return await node.get_channels()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ async def api_delete_channel(
|
||||||
output_index: Optional[int],
|
output_index: Optional[int],
|
||||||
force: bool = False,
|
force: bool = False,
|
||||||
node: Node = Depends(require_node),
|
node: Node = Depends(require_node),
|
||||||
) -> Optional[List[NodeChannel]]:
|
) -> Optional[list[NodeChannel]]:
|
||||||
return await node.close_channel(
|
return await node.close_channel(
|
||||||
short_id,
|
short_id,
|
||||||
(
|
(
|
||||||
|
|
@ -170,7 +170,7 @@ async def api_get_invoices(
|
||||||
|
|
||||||
|
|
||||||
@node_router.get("/peers")
|
@node_router.get("/peers")
|
||||||
async def api_get_peers(node: Node = Depends(require_node)) -> List[NodePeerInfo]:
|
async def api_get_peers(node: Node = Depends(require_node)) -> list[NodePeerInfo]:
|
||||||
return await node.get_peers()
|
return await node.get_peers()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import json
|
||||||
import ssl
|
import ssl
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from math import ceil
|
from math import ceil
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
@ -79,7 +79,7 @@ payment_router = APIRouter(prefix="/api/v1/payments", tags=["Payments"])
|
||||||
name="Payment List",
|
name="Payment List",
|
||||||
summary="get list of payments",
|
summary="get list of payments",
|
||||||
response_description="list of payments",
|
response_description="list of payments",
|
||||||
response_model=List[Payment],
|
response_model=list[Payment],
|
||||||
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
||||||
)
|
)
|
||||||
async def api_payments(
|
async def api_payments(
|
||||||
|
|
@ -98,7 +98,7 @@ async def api_payments(
|
||||||
@payment_router.get(
|
@payment_router.get(
|
||||||
"/history",
|
"/history",
|
||||||
name="Get payments history",
|
name="Get payments history",
|
||||||
response_model=List[PaymentHistoryPoint],
|
response_model=list[PaymentHistoryPoint],
|
||||||
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
||||||
)
|
)
|
||||||
async def api_payments_history(
|
async def api_payments_history(
|
||||||
|
|
@ -113,7 +113,7 @@ async def api_payments_history(
|
||||||
@payment_router.get(
|
@payment_router.get(
|
||||||
"/stats/count",
|
"/stats/count",
|
||||||
name="Get payments history for all users",
|
name="Get payments history for all users",
|
||||||
response_model=List[PaymentCountStat],
|
response_model=list[PaymentCountStat],
|
||||||
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
||||||
)
|
)
|
||||||
async def api_payments_counting_stats(
|
async def api_payments_counting_stats(
|
||||||
|
|
@ -135,7 +135,7 @@ async def api_payments_counting_stats(
|
||||||
@payment_router.get(
|
@payment_router.get(
|
||||||
"/stats/wallets",
|
"/stats/wallets",
|
||||||
name="Get payments history for all users",
|
name="Get payments history for all users",
|
||||||
response_model=List[PaymentWalletStats],
|
response_model=list[PaymentWalletStats],
|
||||||
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
||||||
)
|
)
|
||||||
async def api_payments_wallets_stats(
|
async def api_payments_wallets_stats(
|
||||||
|
|
@ -156,7 +156,7 @@ async def api_payments_wallets_stats(
|
||||||
@payment_router.get(
|
@payment_router.get(
|
||||||
"/stats/daily",
|
"/stats/daily",
|
||||||
name="Get payments history per day",
|
name="Get payments history per day",
|
||||||
response_model=List[PaymentDailyStats],
|
response_model=list[PaymentDailyStats],
|
||||||
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
openapi_extra=generate_filter_params_openapi(PaymentFilters),
|
||||||
)
|
)
|
||||||
async def api_payments_daily_stats(
|
async def api_payments_daily_stats(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import base64
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import shortuuid
|
import shortuuid
|
||||||
|
|
@ -216,7 +216,7 @@ async def api_users_toggle_admin(user_id: str) -> SimpleStatus:
|
||||||
|
|
||||||
|
|
||||||
@users_router.get("/user/{user_id}/wallet", name="Get wallets for user")
|
@users_router.get("/user/{user_id}/wallet", name="Get wallets for user")
|
||||||
async def api_users_get_user_wallet(user_id: str) -> List[Wallet]:
|
async def api_users_get_user_wallet(user_id: str) -> list[Wallet]:
|
||||||
return await get_wallets(user_id)
|
return await get_wallets(user_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Annotated, Literal, Optional, Type, Union
|
from typing import Annotated, Literal, Optional, Union
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from fastapi import Cookie, Depends, Query, Request, Security
|
from fastapi import Cookie, Depends, Query, Request, Security
|
||||||
|
|
@ -223,7 +223,7 @@ async def check_super_user(user: Annotated[User, Depends(check_user_exists)]) ->
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
def parse_filters(model: Type[TFilterModel]):
|
def parse_filters(model: type[TFilterModel]):
|
||||||
"""
|
"""
|
||||||
Parses the query params as filters.
|
Parses the query params as filters.
|
||||||
:param model: model used for validation of filter values
|
:param model: model used for validation of filter values
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import TYPE_CHECKING, AsyncGenerator, Coroutine, NamedTuple
|
from collections.abc import AsyncGenerator, Coroutine
|
||||||
|
from typing import TYPE_CHECKING, NamedTuple
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import AsyncGenerator, Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import json
|
||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Optional, Type
|
from typing import Any, Optional
|
||||||
from urllib import request
|
from urllib import request
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
@ -17,7 +17,6 @@ from pydantic.schema import field_schema
|
||||||
|
|
||||||
from lnbits.jinja2_templating import Jinja2Templates
|
from lnbits.jinja2_templating import Jinja2Templates
|
||||||
from lnbits.nodes import get_node_class
|
from lnbits.nodes import get_node_class
|
||||||
from lnbits.requestvars import g
|
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
from lnbits.utils.crypto import AESCipher
|
from lnbits.utils.crypto import AESCipher
|
||||||
|
|
||||||
|
|
@ -42,7 +41,7 @@ def urlsafe_short_hash() -> str:
|
||||||
|
|
||||||
|
|
||||||
def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> str:
|
def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> str:
|
||||||
base = g().base_url if external else ""
|
base = f"http://{settings.host}:{settings.port}" if external else ""
|
||||||
url_params = "?"
|
url_params = "?"
|
||||||
for key, value in params.items():
|
for key, value in params.items():
|
||||||
url_params += f"{key}={value}&"
|
url_params += f"{key}={value}&"
|
||||||
|
|
@ -154,7 +153,7 @@ def get_current_extension_name() -> str:
|
||||||
return ext_name
|
return ext_name
|
||||||
|
|
||||||
|
|
||||||
def generate_filter_params_openapi(model: Type[FilterModel], keep_optional=False):
|
def generate_filter_params_openapi(model: type[FilterModel], keep_optional=False):
|
||||||
"""
|
"""
|
||||||
Generate openapi documentation for Filters. This is intended to be used along
|
Generate openapi documentation for Filters. This is intended to be used along
|
||||||
parse_filters (see example)
|
parse_filters (see example)
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ class LnurlErrorResponseHandler(APIRoute):
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"LnurlErrorResponse",
|
||||||
|
"LnurlErrorResponseHandler",
|
||||||
"decode",
|
"decode",
|
||||||
"encode",
|
"encode",
|
||||||
"handle",
|
"handle",
|
||||||
"LnurlErrorResponse",
|
|
||||||
"LnurlErrorResponseHandler",
|
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import asyncio
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Any, List, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
from fastapi import FastAPI, Request, Response
|
from fastapi import FastAPI, Request, Response
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
||||||
|
|
@ -61,7 +61,7 @@ class InstalledExtensionMiddleware:
|
||||||
await self.app(scope, receive, send)
|
await self.app(scope, receive, send)
|
||||||
|
|
||||||
def _response_by_accepted_type(
|
def _response_by_accepted_type(
|
||||||
self, scope: Scope, headers: List[Any], msg: str, status_code: HTTPStatus
|
self, scope: Scope, headers: list[Any], msg: str, status_code: HTTPStatus
|
||||||
) -> Union[HTMLResponse, JSONResponse]:
|
) -> Union[HTMLResponse, JSONResponse]:
|
||||||
"""
|
"""
|
||||||
Build an HTTP response containing the `msg` as HTTP body and the `status_code`
|
Build an HTTP response containing the `msg` as HTTP body and the `status_code`
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
import contextvars
|
|
||||||
import types
|
|
||||||
|
|
||||||
request_global = contextvars.ContextVar(
|
|
||||||
"request_global", default=types.SimpleNamespace()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def g() -> types.SimpleNamespace:
|
|
||||||
return request_global.get()
|
|
||||||
|
|
@ -2,11 +2,9 @@ import asyncio
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
|
from collections.abc import Coroutine
|
||||||
from typing import (
|
from typing import (
|
||||||
Callable,
|
Callable,
|
||||||
Coroutine,
|
|
||||||
Dict,
|
|
||||||
List,
|
|
||||||
Optional,
|
Optional,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -22,8 +20,8 @@ from lnbits.core.services.fiat_providers import handle_fiat_payment_confirmation
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
from lnbits.wallets import get_funding_source
|
from lnbits.wallets import get_funding_source
|
||||||
|
|
||||||
tasks: List[asyncio.Task] = []
|
tasks: list[asyncio.Task] = []
|
||||||
unique_tasks: Dict[str, asyncio.Task] = {}
|
unique_tasks: dict[str, asyncio.Task] = {}
|
||||||
|
|
||||||
|
|
||||||
def create_task(coro: Coroutine) -> asyncio.Task:
|
def create_task(coro: Coroutine) -> asyncio.Task:
|
||||||
|
|
@ -83,7 +81,7 @@ async def catch_everything_and_restart(
|
||||||
return await catch_everything_and_restart(func, name)
|
return await catch_everything_and_restart(func, name)
|
||||||
|
|
||||||
|
|
||||||
invoice_listeners: Dict[str, asyncio.Queue] = {}
|
invoice_listeners: dict[str, asyncio.Queue] = {}
|
||||||
|
|
||||||
|
|
||||||
# TODO: name should not be optional
|
# TODO: name should not be optional
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
from typing import Dict, Tuple, Union
|
from typing import Union
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import secp256k1
|
import secp256k1
|
||||||
|
|
@ -13,7 +13,7 @@ from Cryptodome.Util.Padding import pad, unpad
|
||||||
from pynostr.key import PrivateKey
|
from pynostr.key import PrivateKey
|
||||||
|
|
||||||
|
|
||||||
def generate_keypair() -> Tuple[str, str]:
|
def generate_keypair() -> tuple[str, str]:
|
||||||
private_key = PrivateKey()
|
private_key = PrivateKey()
|
||||||
public_key = private_key.public_key
|
public_key = private_key.public_key
|
||||||
return private_key.hex(), public_key.hex()
|
return private_key.hex(), public_key.hex()
|
||||||
|
|
@ -82,7 +82,7 @@ def decrypt_content(
|
||||||
return decrypted
|
return decrypted
|
||||||
|
|
||||||
|
|
||||||
def verify_event(event: Dict) -> bool:
|
def verify_event(event: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
Verify the event signature
|
Verify the event signature
|
||||||
|
|
||||||
|
|
@ -115,8 +115,8 @@ def verify_event(event: Dict) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def sign_event(
|
def sign_event(
|
||||||
event: Dict, account_public_key_hex: str, account_private_key: secp256k1.PrivateKey
|
event: dict, account_public_key_hex: str, account_private_key: secp256k1.PrivateKey
|
||||||
) -> Dict:
|
) -> dict:
|
||||||
"""
|
"""
|
||||||
Signs the event (in place) with the service secret
|
Signs the event (in place) with the service secret
|
||||||
|
|
||||||
|
|
@ -149,7 +149,7 @@ def sign_event(
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
|
||||||
def json_dumps(data: Union[Dict, list]) -> str:
|
def json_dumps(data: Union[dict, list]) -> str:
|
||||||
"""
|
"""
|
||||||
Converts a Python dictionary to a JSON string with compact encoding.
|
Converts a Python dictionary to a JSON string with compact encoding.
|
||||||
|
|
||||||
|
|
@ -159,7 +159,7 @@ def json_dumps(data: Union[Dict, list]) -> str:
|
||||||
Returns:
|
Returns:
|
||||||
str: The compact JSON string.
|
str: The compact JSON string.
|
||||||
"""
|
"""
|
||||||
if isinstance(data, Dict):
|
if isinstance(data, dict):
|
||||||
data = {k: v for k, v in data.items() if v is not None}
|
data = {k: v for k, v in data.items() if v is not None}
|
||||||
return json.dumps(data, separators=(",", ":"), ensure_ascii=False)
|
return json.dumps(data, separators=(",", ":"), ensure_ascii=False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,17 +58,17 @@ __all__ = [
|
||||||
"BlinkWallet",
|
"BlinkWallet",
|
||||||
"BoltzWallet",
|
"BoltzWallet",
|
||||||
"BreezSdkWallet",
|
"BreezSdkWallet",
|
||||||
"ClicheWallet",
|
|
||||||
"CoreLightningWallet",
|
|
||||||
"CLightningWallet",
|
"CLightningWallet",
|
||||||
|
"ClicheWallet",
|
||||||
"CoreLightningRestWallet",
|
"CoreLightningRestWallet",
|
||||||
|
"CoreLightningWallet",
|
||||||
"EclairWallet",
|
"EclairWallet",
|
||||||
"FakeWallet",
|
"FakeWallet",
|
||||||
"LNbitsWallet",
|
|
||||||
"LndWallet",
|
|
||||||
"LndRestWallet",
|
|
||||||
"LNPayWallet",
|
"LNPayWallet",
|
||||||
|
"LNbitsWallet",
|
||||||
"LnTipsWallet",
|
"LnTipsWallet",
|
||||||
|
"LndRestWallet",
|
||||||
|
"LndWallet",
|
||||||
"NWCWallet",
|
"NWCWallet",
|
||||||
"OpenNodeWallet",
|
"OpenNodeWallet",
|
||||||
"PhoenixdWallet",
|
"PhoenixdWallet",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import TYPE_CHECKING, AsyncGenerator, Coroutine, NamedTuple
|
from collections.abc import AsyncGenerator, Coroutine
|
||||||
|
from typing import TYPE_CHECKING, NamedTuple
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from websockets.client import WebSocketClientProtocol, connect
|
from websockets.legacy.client import WebSocketClientProtocol, connect
|
||||||
from websockets.typing import Subprotocol
|
from websockets.typing import Subprotocol
|
||||||
|
|
||||||
from lnbits import bolt11
|
from lnbits import bolt11
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from bolt11.decode import decode
|
from bolt11.decode import decode
|
||||||
from grpc.aio import AioRpcError
|
from grpc.aio import AioRpcError
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ if not BREEZ_SDK_INSTALLED:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import AsyncGenerator, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websocket import create_connection
|
from websocket import create_connection
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ from typing import Any, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websockets.client import connect
|
from websockets.legacy.client import connect
|
||||||
|
|
||||||
from lnbits.helpers import normalize_endpoint
|
from lnbits.helpers import normalize_endpoint
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from os import urandom
|
from os import urandom
|
||||||
from typing import AsyncGenerator, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from bolt11 import (
|
from bolt11 import (
|
||||||
Bolt11,
|
Bolt11,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websockets.client import connect
|
from websockets.legacy.client import connect
|
||||||
|
|
||||||
from lnbits.helpers import normalize_endpoint
|
from lnbits.helpers import normalize_endpoint
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
|
|
@ -75,7 +76,7 @@ class LNbitsWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict = {"out": False, "amount": amount, "memo": memo or ""}
|
data: dict = {"out": False, "amount": amount, "memo": memo or ""}
|
||||||
if kwargs.get("expiry"):
|
if kwargs.get("expiry"):
|
||||||
data["expiry"] = kwargs["expiry"]
|
data["expiry"] = kwargs["expiry"]
|
||||||
if description_hash:
|
if description_hash:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from os import environ
|
from os import environ
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from typing import Optional
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -121,7 +122,7 @@ class LndWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict = {
|
data: dict = {
|
||||||
"description_hash": b"",
|
"description_hash": b"",
|
||||||
"value": amount,
|
"value": amount,
|
||||||
"private": True,
|
"private": True,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ import asyncio
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
from typing import Any, AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -105,7 +106,7 @@ class LndRestWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
_data: Dict = {
|
_data: dict = {
|
||||||
"value": amount,
|
"value": amount,
|
||||||
"private": settings.lnd_rest_route_hints,
|
"private": settings.lnd_rest_route_hints,
|
||||||
"memo": memo or "",
|
"memo": memo or "",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -79,7 +80,7 @@ class LNPayWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**_,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict = {"num_satoshis": f"{amount}"}
|
data: dict = {"num_satoshis": f"{amount}"}
|
||||||
if description_hash:
|
if description_hash:
|
||||||
data["description_hash"] = description_hash.hex()
|
data["description_hash"] = description_hash.hex()
|
||||||
elif unhashed_description:
|
elif unhashed_description:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -73,7 +74,7 @@ class LnTipsWallet(Wallet):
|
||||||
unhashed_description: Optional[bytes] = None,
|
unhashed_description: Optional[bytes] = None,
|
||||||
**_,
|
**_,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
data: Dict = {"amount": amount, "description_hash": "", "memo": memo or ""}
|
data: dict = {"amount": amount, "description_hash": "", "memo": memo or ""}
|
||||||
if description_hash:
|
if description_hash:
|
||||||
data["description_hash"] = description_hash.hex()
|
data["description_hash"] = description_hash.hex()
|
||||||
elif unhashed_description:
|
elif unhashed_description:
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@ import hashlib
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from typing import AsyncGenerator, Dict, List, Optional, Union, cast
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional, Union, cast
|
||||||
from urllib.parse import parse_qs, unquote, urlparse
|
from urllib.parse import parse_qs, unquote, urlparse
|
||||||
|
|
||||||
import secp256k1
|
import secp256k1
|
||||||
from bolt11 import decode as bolt11_decode
|
from bolt11 import decode as bolt11_decode
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websockets.client import connect as ws_connect
|
from websockets.legacy.client import connect as ws_connect
|
||||||
|
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
from lnbits.utils.nostr import (
|
from lnbits.utils.nostr import (
|
||||||
|
|
@ -358,7 +359,7 @@ class NWCConnection:
|
||||||
"""
|
"""
|
||||||
return self.shutdown or not settings.lnbits_running
|
return self.shutdown or not settings.lnbits_running
|
||||||
|
|
||||||
async def _send(self, data: List[Union[str, Dict]]):
|
async def _send(self, data: list[Union[str, dict]]):
|
||||||
"""
|
"""
|
||||||
Sends data to the NWC relay.
|
Sends data to the NWC relay.
|
||||||
|
|
||||||
|
|
@ -394,7 +395,7 @@ class NWCConnection:
|
||||||
|
|
||||||
async def _close_subscription_by_subid(
|
async def _close_subscription_by_subid(
|
||||||
self, sub_id: str, send_event: bool = True
|
self, sub_id: str, send_event: bool = True
|
||||||
) -> Optional[Dict]:
|
) -> Optional[dict]:
|
||||||
"""
|
"""
|
||||||
Closes a subscription by its sub_id.
|
Closes a subscription by its sub_id.
|
||||||
|
|
||||||
|
|
@ -425,7 +426,7 @@ class NWCConnection:
|
||||||
|
|
||||||
async def _close_subscription_by_eventid(
|
async def _close_subscription_by_eventid(
|
||||||
self, event_id, send_event=True
|
self, event_id, send_event=True
|
||||||
) -> Optional[Dict]:
|
) -> Optional[dict]:
|
||||||
"""
|
"""
|
||||||
Closes a subscription associated to an event_id.
|
Closes a subscription associated to an event_id.
|
||||||
|
|
||||||
|
|
@ -498,7 +499,7 @@ class NWCConnection:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Error handling subscription timeout: " + str(e))
|
logger.error("Error handling subscription timeout: " + str(e))
|
||||||
|
|
||||||
async def _on_ok_message(self, msg: List[str]):
|
async def _on_ok_message(self, msg: list[str]):
|
||||||
"""
|
"""
|
||||||
Handles OK messages from the relay.
|
Handles OK messages from the relay.
|
||||||
"""
|
"""
|
||||||
|
|
@ -512,12 +513,12 @@ class NWCConnection:
|
||||||
if subscription: # Check if the subscription exists first
|
if subscription: # Check if the subscription exists first
|
||||||
subscription["future"].set_exception(Exception(info))
|
subscription["future"].set_exception(Exception(info))
|
||||||
|
|
||||||
async def _on_event_message(self, msg: List[Union[str, Dict]]):
|
async def _on_event_message(self, msg: list[Union[str, dict]]):
|
||||||
"""
|
"""
|
||||||
Handles EVENT messages from the relay.
|
Handles EVENT messages from the relay.
|
||||||
"""
|
"""
|
||||||
sub_id = cast(str, msg[1])
|
sub_id = cast(str, msg[1])
|
||||||
event = cast(Dict, msg[2])
|
event = cast(dict, msg[2])
|
||||||
if not verify_event(event): # Ensure the event is valid (do not trust relays)
|
if not verify_event(event): # Ensure the event is valid (do not trust relays)
|
||||||
raise Exception("Invalid event signature")
|
raise Exception("Invalid event signature")
|
||||||
tags = event["tags"]
|
tags = event["tags"]
|
||||||
|
|
@ -571,7 +572,7 @@ class NWCConnection:
|
||||||
else:
|
else:
|
||||||
subscription["future"].set_result(result)
|
subscription["future"].set_result(result)
|
||||||
|
|
||||||
async def _on_closed_message(self, msg: List[str]):
|
async def _on_closed_message(self, msg: list[str]):
|
||||||
"""
|
"""
|
||||||
Handles CLOSED messages from the relay.
|
Handles CLOSED messages from the relay.
|
||||||
"""
|
"""
|
||||||
|
|
@ -646,7 +647,7 @@ class NWCConnection:
|
||||||
logger.debug("Reconnecting to NWC relay in 5 seconds...")
|
logger.debug("Reconnecting to NWC relay in 5 seconds...")
|
||||||
await asyncio.sleep(5)
|
await asyncio.sleep(5)
|
||||||
|
|
||||||
async def call(self, method: str, params: Dict) -> Dict:
|
async def call(self, method: str, params: dict) -> dict:
|
||||||
"""
|
"""
|
||||||
Call a NWC method.
|
Call a NWC method.
|
||||||
|
|
||||||
|
|
@ -708,7 +709,7 @@ class NWCConnection:
|
||||||
# Wait for the response
|
# Wait for the response
|
||||||
return await future
|
return await future
|
||||||
|
|
||||||
async def get_info(self) -> Dict:
|
async def get_info(self) -> dict:
|
||||||
"""
|
"""
|
||||||
Get the info about the service provider and cache it.
|
Get the info about the service provider and cache it.
|
||||||
|
|
||||||
|
|
@ -793,7 +794,7 @@ class NWCConnection:
|
||||||
logger.warning("Error closing connection: " + str(e))
|
logger.warning("Error closing connection: " + str(e))
|
||||||
|
|
||||||
|
|
||||||
def parse_nwc(nwc) -> Dict:
|
def parse_nwc(nwc) -> dict:
|
||||||
"""
|
"""
|
||||||
Parses a NWC URL (nostr+walletconnect://...) and extracts relevant information.
|
Parses a NWC URL (nostr+walletconnect://...) and extracts relevant information.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,12 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
from typing import Any, AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websockets.client import connect
|
from websockets.legacy.client import connect
|
||||||
|
|
||||||
from lnbits.helpers import normalize_endpoint
|
from lnbits.helpers import normalize_endpoint
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
|
|
@ -101,7 +102,7 @@ class PhoenixdWallet(Wallet):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
msats_amount = amount
|
msats_amount = amount
|
||||||
data: Dict[str, Any] = {
|
data: dict[str, Any] = {
|
||||||
"amountSat": f"{msats_amount}",
|
"amountSat": f"{msats_amount}",
|
||||||
"externalId": "",
|
"externalId": "",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
from typing import AsyncGenerator, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, AsyncGenerator, Dict, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
@ -111,8 +112,8 @@ class StrikeWallet(Wallet):
|
||||||
|
|
||||||
# runtime state
|
# runtime state
|
||||||
self.pending_invoices: list[str] = [] # Keep it as a list
|
self.pending_invoices: list[str] = [] # Keep it as a list
|
||||||
self.pending_payments: Dict[str, str] = {}
|
self.pending_payments: dict[str, str] = {}
|
||||||
self.failed_payments: Dict[str, str] = {}
|
self.failed_payments: dict[str, str] = {}
|
||||||
|
|
||||||
# balance cache
|
# balance cache
|
||||||
self._cached_balance: Optional[int] = None
|
self._cached_balance: Optional[int] = None
|
||||||
|
|
@ -183,7 +184,7 @@ class StrikeWallet(Wallet):
|
||||||
if btc and "available" in btc:
|
if btc and "available" in btc:
|
||||||
available_btc = Decimal(btc["available"]) # Get available BTC amount.
|
available_btc = Decimal(btc["available"]) # Get available BTC amount.
|
||||||
msats = int(
|
msats = int(
|
||||||
available_btc * Decimal(1e11)
|
available_btc * Decimal("1e11")
|
||||||
) # Convert BTC to millisatoshis.
|
) # Convert BTC to millisatoshis.
|
||||||
self._cached_balance = msats
|
self._cached_balance = msats
|
||||||
self._cached_balance_ts = now
|
self._cached_balance_ts = now
|
||||||
|
|
@ -204,10 +205,10 @@ class StrikeWallet(Wallet):
|
||||||
**kwargs,
|
**kwargs,
|
||||||
) -> InvoiceResponse:
|
) -> InvoiceResponse:
|
||||||
try:
|
try:
|
||||||
btc_amt = (Decimal(amount) / Decimal(1e8)).quantize(
|
btc_amt = (Decimal(amount) / Decimal("1e8")).quantize(
|
||||||
Decimal("0.00000001")
|
Decimal("0.00000001")
|
||||||
) # Convert amount from millisatoshis to BTC.
|
) # Convert amount from millisatoshis to BTC.
|
||||||
payload: Dict[str, Any] = {
|
payload: dict[str, Any] = {
|
||||||
"bolt11": {
|
"bolt11": {
|
||||||
"amount": {
|
"amount": {
|
||||||
"currency": "BTC",
|
"currency": "BTC",
|
||||||
|
|
@ -270,7 +271,7 @@ class StrikeWallet(Wallet):
|
||||||
# Network fee → msat.
|
# Network fee → msat.
|
||||||
fee_obj = data.get("lightningNetworkFee") or data.get("totalFee") or {}
|
fee_obj = data.get("lightningNetworkFee") or data.get("totalFee") or {}
|
||||||
fee_btc = Decimal(fee_obj.get("amount", "0"))
|
fee_btc = Decimal(fee_obj.get("amount", "0"))
|
||||||
fee_msat = int(fee_btc * Decimal(1e11)) # millisatoshis.
|
fee_msat = int(fee_btc * Decimal("1e11")) # millisatoshis.
|
||||||
|
|
||||||
if state in {"SUCCEEDED", "COMPLETED"}:
|
if state in {"SUCCEEDED", "COMPLETED"}:
|
||||||
preimage = data.get("preimage") or data.get("preImage")
|
preimage = data.get("preimage") or data.get("preImage")
|
||||||
|
|
@ -427,9 +428,9 @@ class StrikeWallet(Wallet):
|
||||||
orderby: Optional[str] = None,
|
orderby: Optional[str] = None,
|
||||||
skip: Optional[int] = None,
|
skip: Optional[int] = None,
|
||||||
top: Optional[int] = None,
|
top: Optional[int] = None,
|
||||||
) -> Dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
try:
|
try:
|
||||||
params: Dict[str, Any] = {}
|
params: dict[str, Any] = {}
|
||||||
if filters:
|
if filters:
|
||||||
params["$filter"] = filters
|
params["$filter"] = filters
|
||||||
if orderby:
|
if orderby:
|
||||||
|
|
@ -465,7 +466,7 @@ class StrikeWallet(Wallet):
|
||||||
try:
|
try:
|
||||||
if currency_str == "BTC":
|
if currency_str == "BTC":
|
||||||
fee_btc_decimal = Decimal(amount_str)
|
fee_btc_decimal = Decimal(amount_str)
|
||||||
fee_msat = int(fee_btc_decimal * Decimal(1e11))
|
fee_msat = int(fee_btc_decimal * Decimal("1e11"))
|
||||||
elif currency_str == "SAT":
|
elif currency_str == "SAT":
|
||||||
fee_sat_decimal = Decimal(amount_str)
|
fee_sat_decimal = Decimal(amount_str)
|
||||||
fee_msat = int(fee_sat_decimal * 1000)
|
fee_msat = int(fee_sat_decimal * 1000)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import AsyncGenerator
|
from collections.abc import AsyncGenerator
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from collections.abc import AsyncGenerator
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
from bolt11 import decode as bolt11_decode
|
from bolt11 import decode as bolt11_decode
|
||||||
|
|
@ -67,7 +68,7 @@ class ZBDWallet(Wallet):
|
||||||
# https://api.zebedee.io/v0/charges
|
# https://api.zebedee.io/v0/charges
|
||||||
|
|
||||||
msats_amount = amount * 1000
|
msats_amount = amount * 1000
|
||||||
data: Dict = {
|
data: dict = {
|
||||||
"amount": f"{msats_amount}",
|
"amount": f"{msats_amount}",
|
||||||
"expiresIn": 3600,
|
"expiresIn": 3600,
|
||||||
"callbackUrl": "",
|
"callbackUrl": "",
|
||||||
|
|
|
||||||
1137
poetry.lock
generated
1137
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -14,49 +14,49 @@ packages = [
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "~3.12 | ~3.11 | ~3.10"
|
python = "~3.12 | ~3.11 | ~3.10"
|
||||||
bech32 = "1.2.0"
|
bech32 = "1.2.0"
|
||||||
click = "8.1.7"
|
click = "8.2.1"
|
||||||
ecdsa = "0.19.0"
|
ecdsa = "0.19.1"
|
||||||
fastapi = "0.115.2"
|
fastapi = "0.115.13"
|
||||||
httpx = "0.27.0"
|
httpx = "0.27.0"
|
||||||
jinja2 = "3.1.4"
|
jinja2 = "3.1.6"
|
||||||
lnurl = "0.5.3"
|
lnurl = "0.5.3"
|
||||||
pydantic = "1.10.18"
|
pydantic = "1.10.18"
|
||||||
pyqrcode = "1.2.1"
|
pyqrcode = "1.2.1"
|
||||||
shortuuid = "1.0.13"
|
shortuuid = "1.0.13"
|
||||||
sse-starlette = "1.8.2"
|
sse-starlette = "2.3.6"
|
||||||
typing-extensions = "4.12.2"
|
typing-extensions = "4.14.0"
|
||||||
uvicorn = "0.34.2"
|
uvicorn = "0.34.3"
|
||||||
sqlalchemy = "1.4.54"
|
sqlalchemy = "1.4.54"
|
||||||
aiosqlite = "0.20.0"
|
aiosqlite = "0.21.0"
|
||||||
asyncpg = "0.30.0"
|
asyncpg = "0.30.0"
|
||||||
uvloop = "0.21.0"
|
uvloop = "0.21.0"
|
||||||
websockets = "11.0.3"
|
websockets = "15.0.1"
|
||||||
loguru = "0.7.2"
|
loguru = "0.7.3"
|
||||||
grpcio = "1.69.0"
|
grpcio = "1.69.0"
|
||||||
protobuf = "5.29.1"
|
protobuf = "5.29.1"
|
||||||
pyln-client = "24.11"
|
pyln-client = "25.5"
|
||||||
pywebpush = "1.14.1"
|
pywebpush = "2.0.3"
|
||||||
slowapi = "0.1.9"
|
slowapi = "0.1.9"
|
||||||
websocket-client = "1.8.0"
|
websocket-client = "1.8.0"
|
||||||
pycryptodomex = "3.20.0"
|
pycryptodomex = "3.23.0"
|
||||||
packaging = "24.0"
|
packaging = "25.0"
|
||||||
bolt11 = "2.1.0"
|
bolt11 = "2.1.1"
|
||||||
pyjwt = "2.9.0"
|
pyjwt = "2.10.1"
|
||||||
passlib = "1.7.4"
|
passlib = "1.7.4"
|
||||||
itsdangerous = "2.2.0"
|
itsdangerous = "2.2.0"
|
||||||
fastapi-sso = "0.15.0"
|
fastapi-sso = "0.18.0"
|
||||||
# needed for boltz, lnurldevice, watchonly extensions
|
# needed for boltz, lnurldevice, watchonly extensions
|
||||||
embit = "0.8.0"
|
embit = "0.8.0"
|
||||||
# needed for cashu, lnurlp, nostrclient, nostrmarket, nostrrelay extensions
|
# needed for cashu, lnurlp, nostrclient, nostrmarket, nostrrelay extensions
|
||||||
secp256k1 = "0.14.0"
|
secp256k1 = "0.14.0"
|
||||||
# keep for backwards compatibility with lnurlp and cashu
|
# keep for backwards compatibility with lnurlp and cashu
|
||||||
environs = "9.5.0"
|
environs = "14.2.0"
|
||||||
# needed for scheduler extension
|
# needed for scheduler extension
|
||||||
python-crontab = "3.2.0"
|
python-crontab = "3.2.0"
|
||||||
# needed for liquid support boltz
|
# needed for liquid support boltz
|
||||||
wallycore = {version = "1.4.0", optional = true}
|
wallycore = {version = "1.4.0", optional = true}
|
||||||
# needed for breez funding source
|
# needed for breez funding source
|
||||||
breez-sdk = {version = "0.6.6", optional = true}
|
breez-sdk = {version = "0.8.0", optional = true}
|
||||||
|
|
||||||
jsonpath-ng = "^1.7.0"
|
jsonpath-ng = "^1.7.0"
|
||||||
pynostr = "^0.6.2"
|
pynostr = "^0.6.2"
|
||||||
|
|
@ -69,15 +69,15 @@ breez = ["breez-sdk"]
|
||||||
liquid = ["wallycore"]
|
liquid = ["wallycore"]
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^24.8.0"
|
black = "^25.1.0"
|
||||||
mypy = "^1.11.2"
|
mypy = "^1.11.2"
|
||||||
types-protobuf = "^5.27.0.20240626"
|
types-protobuf = "^6.30.2.20250516"
|
||||||
pre-commit = "^3.8.0"
|
pre-commit = "^4.2.0"
|
||||||
openapi-spec-validator = "^0.7.1"
|
openapi-spec-validator = "^0.7.1"
|
||||||
ruff = "^0.6.4"
|
ruff = "^0.12.0"
|
||||||
types-passlib = "^1.7.7.20240327"
|
types-passlib = "^1.7.7.20240327"
|
||||||
openai = "^1.39.0"
|
openai = "^1.39.0"
|
||||||
json5 = "^0.9.25"
|
json5 = "^0.12.0"
|
||||||
asgi-lifespan = "^2.1.0"
|
asgi-lifespan = "^2.1.0"
|
||||||
anyio = "^4.7.0"
|
anyio = "^4.7.0"
|
||||||
pytest = "^8.3.4"
|
pytest = "^8.3.4"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import json
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from subprocess import PIPE, Popen, TimeoutExpired
|
from subprocess import PIPE, Popen, TimeoutExpired
|
||||||
from typing import Tuple
|
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
|
@ -84,7 +83,7 @@ def run_cmd_json(cmd: list) -> dict:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def get_hold_invoice(sats: int) -> Tuple[str, dict]:
|
def get_hold_invoice(sats: int) -> tuple[str, dict]:
|
||||||
preimage = os.urandom(32)
|
preimage = os.urandom(32)
|
||||||
preimage_hash = hashlib.sha256(preimage).hexdigest()
|
preimage_hash = hashlib.sha256(preimage).hexdigest()
|
||||||
cmd = docker_lightning_cli.copy()
|
cmd = docker_lightning_cli.copy()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Dict, List, Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
@ -41,24 +41,24 @@ class Mock(FunctionMock, TestMock):
|
||||||
|
|
||||||
|
|
||||||
class FunctionMocks(BaseModel):
|
class FunctionMocks(BaseModel):
|
||||||
mocks: Dict[str, FunctionMock]
|
mocks: dict[str, FunctionMock]
|
||||||
|
|
||||||
|
|
||||||
class FunctionTest(BaseModel):
|
class FunctionTest(BaseModel):
|
||||||
description: str
|
description: str
|
||||||
call_params: dict
|
call_params: dict
|
||||||
expect: dict
|
expect: dict
|
||||||
mocks: Dict[str, List[Dict[str, TestMock]]]
|
mocks: dict[str, list[dict[str, TestMock]]]
|
||||||
|
|
||||||
|
|
||||||
class FunctionData(BaseModel):
|
class FunctionData(BaseModel):
|
||||||
"""Data required for testing this function"""
|
"""Data required for testing this function"""
|
||||||
|
|
||||||
"Function level mocks that apply for all tests of this function"
|
"Function level mocks that apply for all tests of this function"
|
||||||
mocks: List[FunctionMock] = []
|
mocks: list[FunctionMock] = []
|
||||||
|
|
||||||
"All the tests for this function"
|
"All the tests for this function"
|
||||||
tests: List[FunctionTest] = []
|
tests: list[FunctionTest] = []
|
||||||
|
|
||||||
|
|
||||||
class WalletTest(BaseModel):
|
class WalletTest(BaseModel):
|
||||||
|
|
@ -69,7 +69,7 @@ class WalletTest(BaseModel):
|
||||||
call_params: Optional[dict] = {}
|
call_params: Optional[dict] = {}
|
||||||
expect: Optional[dict]
|
expect: Optional[dict]
|
||||||
expect_error: Optional[dict]
|
expect_error: Optional[dict]
|
||||||
mocks: List[Mock] = []
|
mocks: list[Mock] = []
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def tests_for_funding_source(
|
def tests_for_funding_source(
|
||||||
|
|
@ -77,7 +77,7 @@ class WalletTest(BaseModel):
|
||||||
fn_name: str,
|
fn_name: str,
|
||||||
fn,
|
fn,
|
||||||
test,
|
test,
|
||||||
) -> List["WalletTest"]:
|
) -> list["WalletTest"]:
|
||||||
t = WalletTest(
|
t = WalletTest(
|
||||||
**{
|
**{
|
||||||
"funding_source": fs,
|
"funding_source": fs,
|
||||||
|
|
@ -96,7 +96,7 @@ class WalletTest(BaseModel):
|
||||||
|
|
||||||
return [t]
|
return [t]
|
||||||
|
|
||||||
def _tests_from_fs_mocks(self, fn, test, fs_name: str) -> List["WalletTest"]:
|
def _tests_from_fs_mocks(self, fn, test, fs_name: str) -> list["WalletTest"]:
|
||||||
|
|
||||||
fs_mocks = fn["mocks"][fs_name]
|
fs_mocks = fn["mocks"][fs_name]
|
||||||
test_mocks = test["mocks"][fs_name]
|
test_mocks = test["mocks"][fs_name]
|
||||||
|
|
@ -132,7 +132,7 @@ class WalletTest(BaseModel):
|
||||||
|
|
||||||
def _tests_from_mock(self, mock_obj) -> "WalletTest":
|
def _tests_from_mock(self, mock_obj) -> "WalletTest":
|
||||||
|
|
||||||
test_mocks: List[Mock] = [
|
test_mocks: list[Mock] = [
|
||||||
Mock.combine_mocks(
|
Mock.combine_mocks(
|
||||||
mock_name,
|
mock_name,
|
||||||
mock_obj[mock_name]["fs_mock"],
|
mock_obj[mock_name]["fs_mock"],
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import functools
|
||||||
import importlib
|
import importlib
|
||||||
import json
|
import json
|
||||||
import operator
|
import operator
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
@ -12,7 +11,7 @@ from tests.wallets.fixtures.models import FundingSourceConfig, WalletTest
|
||||||
wallets_module = importlib.import_module("lnbits.wallets")
|
wallets_module = importlib.import_module("lnbits.wallets")
|
||||||
|
|
||||||
|
|
||||||
def wallet_fixtures_from_json(path) -> List["WalletTest"]:
|
def wallet_fixtures_from_json(path) -> list["WalletTest"]:
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
|
|
||||||
|
|
@ -20,7 +19,7 @@ def wallet_fixtures_from_json(path) -> List["WalletTest"]:
|
||||||
FundingSourceConfig(name=fs_name, **data["funding_sources"][fs_name])
|
FundingSourceConfig(name=fs_name, **data["funding_sources"][fs_name])
|
||||||
for fs_name in data["funding_sources"]
|
for fs_name in data["funding_sources"]
|
||||||
]
|
]
|
||||||
tests: Dict[str, List[WalletTest]] = {}
|
tests: dict[str, list[WalletTest]] = {}
|
||||||
for fn_name in data["functions"]:
|
for fn_name in data["functions"]:
|
||||||
fn = data["functions"][fn_name]
|
fn = data["functions"][fn_name]
|
||||||
fn_tests = _tests_for_function(funding_sources, fn_name, fn)
|
fn_tests = _tests_for_function(funding_sources, fn_name, fn)
|
||||||
|
|
@ -33,9 +32,9 @@ def wallet_fixtures_from_json(path) -> List["WalletTest"]:
|
||||||
|
|
||||||
|
|
||||||
def _tests_for_function(
|
def _tests_for_function(
|
||||||
funding_sources: List[FundingSourceConfig], fn_name: str, fn
|
funding_sources: list[FundingSourceConfig], fn_name: str, fn
|
||||||
) -> Dict[str, List[WalletTest]]:
|
) -> dict[str, list[WalletTest]]:
|
||||||
tests: Dict[str, List[WalletTest]] = {}
|
tests: dict[str, list[WalletTest]] = {}
|
||||||
for test in fn["tests"]:
|
for test in fn["tests"]:
|
||||||
"""create an unit test for each funding source"""
|
"""create an unit test for each funding source"""
|
||||||
|
|
||||||
|
|
@ -46,9 +45,9 @@ def _tests_for_function(
|
||||||
|
|
||||||
|
|
||||||
def _tests_for_funding_source(
|
def _tests_for_funding_source(
|
||||||
funding_sources: List[FundingSourceConfig], fn_name: str, fn, test
|
funding_sources: list[FundingSourceConfig], fn_name: str, fn, test
|
||||||
) -> Dict[str, List[WalletTest]]:
|
) -> dict[str, list[WalletTest]]:
|
||||||
tests: Dict[str, List[WalletTest]] = {fs.name: [] for fs in funding_sources}
|
tests: dict[str, list[WalletTest]] = {fs.name: [] for fs in funding_sources}
|
||||||
for fs in funding_sources:
|
for fs in funding_sources:
|
||||||
tests[fs.name] += WalletTest.tests_for_funding_source(fs, fn_name, fn, test)
|
tests[fs.name] += WalletTest.tests_for_funding_source(fs, fn_name, fn, test)
|
||||||
return tests
|
return tests
|
||||||
|
|
@ -132,7 +131,7 @@ async def _assert_error(wallet, tested_func, call_params, expect_error):
|
||||||
assert e_info.match(expect_error["message"])
|
assert e_info.match(expect_error["message"])
|
||||||
|
|
||||||
|
|
||||||
def _merge_dict_of_lists(v1: Dict[str, List], v2: Dict[str, List]):
|
def _merge_dict_of_lists(v1: dict[str, list], v2: dict[str, list]):
|
||||||
"""Merge v2 into v1"""
|
"""Merge v2 into v1"""
|
||||||
for k in v2:
|
for k in v2:
|
||||||
v1[k] = v2[k] if k not in v1 else v1[k] + v2[k]
|
v1[k] = v2[k] if k not in v1 else v1[k] + v2[k]
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from typing import Dict, cast
|
from typing import cast
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import secp256k1
|
import secp256k1
|
||||||
from Cryptodome import Random
|
from Cryptodome import Random
|
||||||
from Cryptodome.Cipher import AES
|
from Cryptodome.Cipher import AES
|
||||||
from Cryptodome.Util.Padding import pad, unpad
|
from Cryptodome.Util.Padding import pad, unpad
|
||||||
from websockets.server import serve as ws_serve
|
from websockets.legacy.server import serve as ws_serve
|
||||||
|
|
||||||
from lnbits.wallets.nwc import NWCWallet
|
from lnbits.wallets.nwc import NWCWallet
|
||||||
from tests.wallets.helpers import (
|
from tests.wallets.helpers import (
|
||||||
|
|
@ -49,7 +49,7 @@ def decrypt_content(priv_key, source_pub_key, content):
|
||||||
|
|
||||||
|
|
||||||
def json_dumps(data):
|
def json_dumps(data):
|
||||||
if isinstance(data, Dict):
|
if isinstance(data, dict):
|
||||||
data = {k: v for k, v in data.items() if v is not None}
|
data = {k: v for k, v in data.items() if v is not None}
|
||||||
return json.dumps(data, separators=(",", ":"), ensure_ascii=False)
|
return json.dumps(data, separators=(",", ":"), ensure_ascii=False)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import json
|
import json
|
||||||
from typing import Dict, Union
|
from typing import Union
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -59,7 +59,7 @@ async def test_rest_wallet(httpserver: HTTPServer, test_data: WalletTest):
|
||||||
|
|
||||||
|
|
||||||
def _apply_mock(httpserver: HTTPServer, mock: Mock):
|
def _apply_mock(httpserver: HTTPServer, mock: Mock):
|
||||||
request_data: Dict[str, Union[str, dict, list]] = {}
|
request_data: dict[str, Union[str, dict, list]] = {}
|
||||||
request_type = getattr(mock.dict(), "request_type", None)
|
request_type = getattr(mock.dict(), "request_type", None)
|
||||||
# request_type = mock.request_type <--- this des not work for whatever reason!!!
|
# request_type = mock.request_type <--- this des not work for whatever reason!!!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import importlib
|
import importlib
|
||||||
from typing import Dict, List, Optional
|
from typing import Optional
|
||||||
from unittest.mock import AsyncMock, Mock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
@ -93,7 +93,7 @@ def _check_calls(expected_calls):
|
||||||
|
|
||||||
|
|
||||||
def _spy_mocks(mocker: MockerFixture, test_data: WalletTest, wallet: BaseWallet):
|
def _spy_mocks(mocker: MockerFixture, test_data: WalletTest, wallet: BaseWallet):
|
||||||
expected_calls: Dict[str, List] = {}
|
expected_calls: dict[str, list] = {}
|
||||||
for mock in test_data.mocks:
|
for mock in test_data.mocks:
|
||||||
client_field = getattr(wallet, mock.name)
|
client_field = getattr(wallet, mock.name)
|
||||||
spy = _spy_mock(mocker, mock, client_field)
|
spy = _spy_mock(mocker, mock, client_field)
|
||||||
|
|
@ -104,7 +104,7 @@ def _spy_mocks(mocker: MockerFixture, test_data: WalletTest, wallet: BaseWallet)
|
||||||
|
|
||||||
def _spy_mock(mocker: MockerFixture, mock: RpcMock, client_field):
|
def _spy_mock(mocker: MockerFixture, mock: RpcMock, client_field):
|
||||||
|
|
||||||
expected_calls: Dict[str, List] = {}
|
expected_calls: dict[str, list] = {}
|
||||||
assert isinstance(mock.response, dict), "Expected data RPC response"
|
assert isinstance(mock.response, dict), "Expected data RPC response"
|
||||||
for field_name in mock.response:
|
for field_name in mock.response:
|
||||||
value = mock.response[field_name]
|
value = mock.response[field_name]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import argparse
|
||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Optional
|
from typing import Optional
|
||||||
|
|
||||||
from lnbits.settings import settings
|
from lnbits.settings import settings
|
||||||
|
|
||||||
|
|
@ -108,7 +108,7 @@ def insert_to_pg(query, data):
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
|
|
||||||
def migrate_core(file: str, exclude_tables: Optional[List[str]] = None):
|
def migrate_core(file: str, exclude_tables: Optional[list[str]] = None):
|
||||||
if exclude_tables is None:
|
if exclude_tables is None:
|
||||||
exclude_tables = []
|
exclude_tables = []
|
||||||
print(f"Migrating core: {file}")
|
print(f"Migrating core: {file}")
|
||||||
|
|
@ -124,7 +124,7 @@ def migrate_ext(file: str):
|
||||||
print(f"✅ Migrated ext: {schema}")
|
print(f"✅ Migrated ext: {schema}")
|
||||||
|
|
||||||
|
|
||||||
def migrate_db(file: str, schema: str, exclude_tables: Optional[List[str]] = None):
|
def migrate_db(file: str, schema: str, exclude_tables: Optional[list[str]] = None):
|
||||||
# first we check if this file exists:
|
# first we check if this file exists:
|
||||||
if exclude_tables is None:
|
if exclude_tables is None:
|
||||||
exclude_tables = []
|
exclude_tables = []
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue