chore: add uv, add ci, fix some issues (#113)
Some checks are pending
CI / lint (push) Waiting to run

in preparation of removing secp
This commit is contained in:
dni ⚡ 2025-10-30 10:11:18 +01:00 committed by GitHub
parent 499b1f81f1
commit 3a8c16d155
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 2482 additions and 2775 deletions

10
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,10 @@
name: CI
on:
push:
branches:
- main
pull_request:
jobs:
lint:
uses: lnbits/lnbits/.github/workflows/lint.yml@dev

View file

@ -5,27 +5,27 @@ format: prettier black ruff
check: mypy pyright checkblack checkruff checkprettier
prettier:
poetry run ./node_modules/.bin/prettier --write .
uv run ./node_modules/.bin/prettier --write .
pyright:
poetry run ./node_modules/.bin/pyright
uv run ./node_modules/.bin/pyright
mypy:
poetry run mypy .
uv run mypy .
black:
poetry run black .
uv run black .
ruff:
poetry run ruff check . --fix
uv run ruff check . --fix
checkruff:
poetry run ruff check .
uv run ruff check .
checkprettier:
poetry run ./node_modules/.bin/prettier --check .
uv run ./node_modules/.bin/prettier --check .
checkblack:
poetry run black --check .
uv run black --check .
checkeditorconfig:
editorconfig-checker
@ -33,14 +33,14 @@ checkeditorconfig:
test:
PYTHONUNBUFFERED=1 \
DEBUG=true \
poetry run pytest
uv run pytest
install-pre-commit-hook:
@echo "Installing pre-commit hook to git"
@echo "Uninstall the hook with poetry run pre-commit uninstall"
poetry run pre-commit install
@echo "Uninstall the hook with uv run pre-commit uninstall"
uv run pre-commit install
pre-commit:
poetry run pre-commit run --all-files
uv run pre-commit run --all-files
checkbundle:

69
crud.py
View file

@ -1,5 +1,4 @@
import json
from typing import List, Optional, Tuple
from lnbits.helpers import urlsafe_short_hash
@ -44,7 +43,7 @@ async def create_merchant(user_id: str, m: PartialMerchant) -> Merchant:
async def update_merchant(
user_id: str, merchant_id: str, config: MerchantConfig
) -> Optional[Merchant]:
) -> Merchant | None:
await db.execute(
f"""
UPDATE nostrmarket.merchants SET meta = :meta, time = {db.timestamp_now}
@ -55,7 +54,7 @@ async def update_merchant(
return await get_merchant(user_id, merchant_id)
async def touch_merchant(user_id: str, merchant_id: str) -> Optional[Merchant]:
async def touch_merchant(user_id: str, merchant_id: str) -> Merchant | None:
await db.execute(
f"""
UPDATE nostrmarket.merchants SET time = {db.timestamp_now}
@ -66,7 +65,7 @@ async def touch_merchant(user_id: str, merchant_id: str) -> Optional[Merchant]:
return await get_merchant(user_id, merchant_id)
async def get_merchant(user_id: str, merchant_id: str) -> Optional[Merchant]:
async def get_merchant(user_id: str, merchant_id: str) -> Merchant | None:
row: dict = await db.fetchone(
"""SELECT * FROM nostrmarket.merchants WHERE user_id = :user_id AND id = :id""",
{
@ -78,7 +77,7 @@ async def get_merchant(user_id: str, merchant_id: str) -> Optional[Merchant]:
return Merchant.from_row(row) if row else None
async def get_merchant_by_pubkey(public_key: str) -> Optional[Merchant]:
async def get_merchant_by_pubkey(public_key: str) -> Merchant | None:
row: dict = await db.fetchone(
"""SELECT * FROM nostrmarket.merchants WHERE public_key = :public_key""",
{"public_key": public_key},
@ -87,7 +86,7 @@ async def get_merchant_by_pubkey(public_key: str) -> Optional[Merchant]:
return Merchant.from_row(row) if row else None
async def get_merchants_ids_with_pubkeys() -> List[Tuple[str, str]]:
async def get_merchants_ids_with_pubkeys() -> list[tuple[str, str]]:
rows: list[dict] = await db.fetchall(
"""SELECT id, public_key FROM nostrmarket.merchants""",
)
@ -95,7 +94,7 @@ async def get_merchants_ids_with_pubkeys() -> List[Tuple[str, str]]:
return [(row["id"], row["public_key"]) for row in rows]
async def get_merchant_for_user(user_id: str) -> Optional[Merchant]:
async def get_merchant_for_user(user_id: str) -> Merchant | None:
row: dict = await db.fetchone(
"""SELECT * FROM nostrmarket.merchants WHERE user_id = :user_id """,
{"user_id": user_id},
@ -138,7 +137,7 @@ async def create_zone(merchant_id: str, data: Zone) -> Zone:
return zone
async def update_zone(merchant_id: str, z: Zone) -> Optional[Zone]:
async def update_zone(merchant_id: str, z: Zone) -> Zone | None:
await db.execute(
"""
UPDATE nostrmarket.zones
@ -157,7 +156,7 @@ async def update_zone(merchant_id: str, z: Zone) -> Optional[Zone]:
return await get_zone(merchant_id, z.id)
async def get_zone(merchant_id: str, zone_id: str) -> Optional[Zone]:
async def get_zone(merchant_id: str, zone_id: str) -> Zone | None:
row: dict = await db.fetchone(
"SELECT * FROM nostrmarket.zones WHERE merchant_id = :merchant_id AND id = :id",
{
@ -168,7 +167,7 @@ async def get_zone(merchant_id: str, zone_id: str) -> Optional[Zone]:
return Zone.from_row(row) if row else None
async def get_zones(merchant_id: str) -> List[Zone]:
async def get_zones(merchant_id: str) -> list[Zone]:
rows: list[dict] = await db.fetchall(
"SELECT * FROM nostrmarket.zones WHERE merchant_id = :merchant_id",
{"merchant_id": merchant_id},
@ -235,7 +234,7 @@ async def create_stall(merchant_id: str, data: Stall) -> Stall:
return stall
async def get_stall(merchant_id: str, stall_id: str) -> Optional[Stall]:
async def get_stall(merchant_id: str, stall_id: str) -> Stall | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.stalls
@ -249,7 +248,7 @@ async def get_stall(merchant_id: str, stall_id: str) -> Optional[Stall]:
return Stall.from_row(row) if row else None
async def get_stalls(merchant_id: str, pending: Optional[bool] = False) -> List[Stall]:
async def get_stalls(merchant_id: str, pending: bool | None = False) -> list[Stall]:
rows: list[dict] = await db.fetchall(
"""
SELECT * FROM nostrmarket.stalls
@ -274,7 +273,7 @@ async def get_last_stall_update_time() -> int:
return row["event_created_at"] or 0 if row else 0
async def update_stall(merchant_id: str, stall: Stall) -> Optional[Stall]:
async def update_stall(merchant_id: str, stall: Stall) -> Stall | None:
await db.execute(
"""
UPDATE nostrmarket.stalls
@ -398,9 +397,7 @@ async def update_product(merchant_id: str, product: Product) -> Product:
return updated_product
async def update_product_quantity(
product_id: str, new_quantity: int
) -> Optional[Product]:
async def update_product_quantity(product_id: str, new_quantity: int) -> Product | None:
await db.execute(
"""
UPDATE nostrmarket.products SET quantity = :quantity
@ -415,7 +412,7 @@ async def update_product_quantity(
return Product.from_row(row) if row else None
async def get_product(merchant_id: str, product_id: str) -> Optional[Product]:
async def get_product(merchant_id: str, product_id: str) -> Product | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.products
@ -431,8 +428,8 @@ async def get_product(merchant_id: str, product_id: str) -> Optional[Product]:
async def get_products(
merchant_id: str, stall_id: str, pending: Optional[bool] = False
) -> List[Product]:
merchant_id: str, stall_id: str, pending: bool | None = False
) -> list[Product]:
rows: list[dict] = await db.fetchall(
"""
SELECT * FROM nostrmarket.products
@ -445,8 +442,8 @@ async def get_products(
async def get_products_by_ids(
merchant_id: str, product_ids: List[str]
) -> List[Product]:
merchant_id: str, product_ids: list[str]
) -> list[Product]:
# todo: revisit
keys = []
@ -467,7 +464,7 @@ async def get_products_by_ids(
return [Product.from_row(row) for row in rows]
async def get_wallet_for_product(product_id: str) -> Optional[str]:
async def get_wallet_for_product(product_id: str) -> str | None:
row: dict = await db.fetchone(
"""
SELECT s.wallet as wallet FROM nostrmarket.products p
@ -574,7 +571,7 @@ async def create_order(merchant_id: str, o: Order) -> Order:
return order
async def get_order(merchant_id: str, order_id: str) -> Optional[Order]:
async def get_order(merchant_id: str, order_id: str) -> Order | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.orders
@ -588,7 +585,7 @@ async def get_order(merchant_id: str, order_id: str) -> Optional[Order]:
return Order.from_row(row) if row else None
async def get_order_by_event_id(merchant_id: str, event_id: str) -> Optional[Order]:
async def get_order_by_event_id(merchant_id: str, event_id: str) -> Order | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.orders
@ -602,7 +599,7 @@ async def get_order_by_event_id(merchant_id: str, event_id: str) -> Optional[Ord
return Order.from_row(row) if row else None
async def get_orders(merchant_id: str, **kwargs) -> List[Order]:
async def get_orders(merchant_id: str, **kwargs) -> list[Order]:
q = " AND ".join(
[
f"{field[0]} = :{field[0]}"
@ -629,7 +626,7 @@ async def get_orders(merchant_id: str, **kwargs) -> List[Order]:
async def get_orders_for_stall(
merchant_id: str, stall_id: str, **kwargs
) -> List[Order]:
) -> list[Order]:
q = " AND ".join(
[
f"{field[0]} = :{field[0]}"
@ -654,7 +651,7 @@ async def get_orders_for_stall(
return [Order.from_row(row) for row in rows]
async def update_order(merchant_id: str, order_id: str, **kwargs) -> Optional[Order]:
async def update_order(merchant_id: str, order_id: str, **kwargs) -> Order | None:
q = ", ".join(
[
f"{field[0]} = :{field[0]}"
@ -678,7 +675,7 @@ async def update_order(merchant_id: str, order_id: str, **kwargs) -> Optional[Or
return await get_order(merchant_id, order_id)
async def update_order_paid_status(order_id: str, paid: bool) -> Optional[Order]:
async def update_order_paid_status(order_id: str, paid: bool) -> Order | None:
await db.execute(
"UPDATE nostrmarket.orders SET paid = :paid WHERE id = :id",
{"paid": paid, "id": order_id},
@ -692,7 +689,7 @@ async def update_order_paid_status(order_id: str, paid: bool) -> Optional[Order]
async def update_order_shipped_status(
merchant_id: str, order_id: str, shipped: bool
) -> Optional[Order]:
) -> Order | None:
await db.execute(
"""
UPDATE nostrmarket.orders
@ -756,7 +753,7 @@ async def create_direct_message(
return msg
async def get_direct_message(merchant_id: str, dm_id: str) -> Optional[DirectMessage]:
async def get_direct_message(merchant_id: str, dm_id: str) -> DirectMessage | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.direct_messages
@ -772,7 +769,7 @@ async def get_direct_message(merchant_id: str, dm_id: str) -> Optional[DirectMes
async def get_direct_message_by_event_id(
merchant_id: str, event_id: str
) -> Optional[DirectMessage]:
) -> DirectMessage | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.direct_messages
@ -786,7 +783,7 @@ async def get_direct_message_by_event_id(
return DirectMessage.from_row(row) if row else None
async def get_direct_messages(merchant_id: str, public_key: str) -> List[DirectMessage]:
async def get_direct_messages(merchant_id: str, public_key: str) -> list[DirectMessage]:
rows: list[dict] = await db.fetchall(
"""
SELECT * FROM nostrmarket.direct_messages
@ -798,7 +795,7 @@ async def get_direct_messages(merchant_id: str, public_key: str) -> List[DirectM
return [DirectMessage.from_row(row) for row in rows]
async def get_orders_from_direct_messages(merchant_id: str) -> List[DirectMessage]:
async def get_orders_from_direct_messages(merchant_id: str) -> list[DirectMessage]:
rows: list[dict] = await db.fetchall(
"""
SELECT * FROM nostrmarket.direct_messages
@ -859,7 +856,7 @@ async def create_customer(merchant_id: str, data: Customer) -> Customer:
return customer
async def get_customer(merchant_id: str, public_key: str) -> Optional[Customer]:
async def get_customer(merchant_id: str, public_key: str) -> Customer | None:
row: dict = await db.fetchone(
"""
SELECT * FROM nostrmarket.customers
@ -873,7 +870,7 @@ async def get_customer(merchant_id: str, public_key: str) -> Optional[Customer]:
return Customer.from_row(row) if row else None
async def get_customers(merchant_id: str) -> List[Customer]:
async def get_customers(merchant_id: str) -> list[Customer]:
rows: list[dict] = await db.fetchall(
"SELECT * FROM nostrmarket.customers WHERE merchant_id = :merchant_id",
{"merchant_id": merchant_id},
@ -881,7 +878,7 @@ async def get_customers(merchant_id: str) -> List[Customer]:
return [Customer.from_row(row) for row in rows]
async def get_all_unique_customers() -> List[Customer]:
async def get_all_unique_customers() -> list[Customer]:
q = """
SELECT public_key, MAX(merchant_id) as merchant_id, MAX(event_created_at)
FROM nostrmarket.customers

View file

@ -1,6 +1,5 @@
import base64
import secrets
from typing import Optional
import secp256k1
from bech32 import bech32_decode, convertbits
@ -33,7 +32,7 @@ def decrypt_message(encoded_message: str, encryption_key) -> str:
return unpadded_data.decode()
def encrypt_message(message: str, encryption_key, iv: Optional[bytes] = None) -> str:
def encrypt_message(message: str, encryption_key, iv: bytes | None = None) -> str:
padder = padding.PKCS7(128).padder()
padded_data = padder.update(message.encode()) + padder.finalize()

116
models.py
View file

@ -2,7 +2,7 @@ import json
import time
from abc import abstractmethod
from enum import Enum
from typing import Any, List, Optional, Tuple
from typing import Any
from lnbits.utils.exchange_rates import btc_price, fiat_amount_as_satoshis
from pydantic import BaseModel
@ -32,16 +32,16 @@ class Nostrable:
class MerchantProfile(BaseModel):
name: Optional[str] = None
about: Optional[str] = None
picture: Optional[str] = None
name: str | None = None
about: str | None = None
picture: str | None = None
class MerchantConfig(MerchantProfile):
event_id: Optional[str] = None
sync_from_nostr = False
event_id: str | None = None
sync_from_nostr: bool = False
active: bool = False
restore_in_progress: Optional[bool] = False
restore_in_progress: bool | None = False
class PartialMerchant(BaseModel):
@ -52,7 +52,7 @@ class PartialMerchant(BaseModel):
class Merchant(PartialMerchant, Nostrable):
id: str
time: Optional[int] = 0
time: int | None = 0
def sign_hash(self, hash_: bytes) -> str:
return sign_message_hash(self.private_key, hash_)
@ -122,11 +122,11 @@ class Merchant(PartialMerchant, Nostrable):
######################################## ZONES ########################################
class Zone(BaseModel):
id: Optional[str] = None
name: Optional[str] = None
id: str | None = None
name: str | None = None
currency: str
cost: float
countries: List[str] = []
countries: list[str] = []
@classmethod
def from_row(cls, row: dict) -> "Zone":
@ -139,22 +139,22 @@ class Zone(BaseModel):
class StallConfig(BaseModel):
image_url: Optional[str] = None
description: Optional[str] = None
image_url: str | None = None
description: str | None = None
class Stall(BaseModel, Nostrable):
id: Optional[str] = None
id: str | None = None
wallet: str
name: str
currency: str = "sat"
shipping_zones: List[Zone] = []
shipping_zones: list[Zone] = []
config: StallConfig = StallConfig()
pending: bool = False
"""Last published nostr event for this Stall"""
event_id: Optional[str] = None
event_created_at: Optional[int] = None
event_id: str | None = None
event_created_at: int | None = None
def validate_stall(self):
for z in self.shipping_zones:
@ -212,19 +212,19 @@ class ProductShippingCost(BaseModel):
class ProductConfig(BaseModel):
description: Optional[str] = None
currency: Optional[str] = None
use_autoreply: Optional[bool] = False
autoreply_message: Optional[str] = None
shipping: List[ProductShippingCost] = []
description: str | None = None
currency: str | None = None
use_autoreply: bool | None = False
autoreply_message: str | None = None
shipping: list[ProductShippingCost] = []
class Product(BaseModel, Nostrable):
id: Optional[str] = None
id: str | None = None
stall_id: str
name: str
categories: List[str] = []
images: List[str] = []
categories: list[str] = []
images: list[str] = []
price: float
quantity: int
active: bool = True
@ -232,8 +232,8 @@ class Product(BaseModel, Nostrable):
config: ProductConfig = ProductConfig()
"""Last published nostr event for this Product"""
event_id: Optional[str] = None
event_created_at: Optional[int] = None
event_id: str | None = None
event_created_at: int | None = None
def to_nostr_event(self, pubkey: str) -> NostrEvent:
content = {
@ -290,7 +290,7 @@ class ProductOverview(BaseModel):
id: str
name: str
price: float
product_shipping_cost: Optional[float] = None
product_shipping_cost: float | None = None
@classmethod
def from_product(cls, p: Product) -> "ProductOverview":
@ -307,21 +307,21 @@ class OrderItem(BaseModel):
class OrderContact(BaseModel):
nostr: Optional[str] = None
phone: Optional[str] = None
email: Optional[str] = None
nostr: str | None = None
phone: str | None = None
email: str | None = None
class OrderExtra(BaseModel):
products: List[ProductOverview]
products: list[ProductOverview]
currency: str
btc_price: str
shipping_cost: float = 0
shipping_cost_sat: float = 0
fail_message: Optional[str] = None
fail_message: str | None = None
@classmethod
async def from_products(cls, products: List[Product]):
async def from_products(cls, products: list[Product]):
currency = products[0].config.currency if len(products) else "sat"
exchange_rate = (
await btc_price(currency) if currency and currency != "sat" else 1
@ -337,19 +337,19 @@ class OrderExtra(BaseModel):
class PartialOrder(BaseModel):
id: str
event_id: Optional[str] = None
event_created_at: Optional[int] = None
event_id: str | None = None
event_created_at: int | None = None
public_key: str
merchant_public_key: str
shipping_id: str
items: List[OrderItem]
contact: Optional[OrderContact] = None
address: Optional[str] = None
items: list[OrderItem]
contact: OrderContact | None = None
address: str | None = None
def validate_order(self):
assert len(self.items) != 0, f"Order has no items. Order: '{self.id}'"
def validate_order_items(self, product_list: List[Product]):
def validate_order_items(self, product_list: list[Product]):
assert len(self.items) != 0, f"Order has no items. Order: '{self.id}'"
assert (
len(product_list) != 0
@ -370,8 +370,8 @@ class PartialOrder(BaseModel):
)
async def costs_in_sats(
self, products: List[Product], shipping_id: str, stall_shipping_cost: float
) -> Tuple[float, float]:
self, products: list[Product], shipping_id: str, stall_shipping_cost: float
) -> tuple[float, float]:
product_prices = {}
for p in products:
product_shipping_cost = next(
@ -400,7 +400,7 @@ class PartialOrder(BaseModel):
return product_cost, stall_shipping_cost
def receipt(
self, products: List[Product], shipping_id: str, stall_shipping_cost: float
self, products: list[Product], shipping_id: str, stall_shipping_cost: float
) -> str:
if len(products) == 0:
return "[No Products]"
@ -449,7 +449,7 @@ class Order(PartialOrder):
total: float
paid: bool = False
shipped: bool = False
time: Optional[int] = None
time: int | None = None
extra: OrderExtra
@classmethod
@ -463,14 +463,14 @@ class Order(PartialOrder):
class OrderStatusUpdate(BaseModel):
id: str
message: Optional[str] = None
paid: Optional[bool] = False
shipped: Optional[bool] = None
message: str | None = None
paid: bool | None = False
shipped: bool | None = None
class OrderReissue(BaseModel):
id: str
shipping_id: Optional[str] = None
shipping_id: str | None = None
class PaymentOption(BaseModel):
@ -480,8 +480,8 @@ class PaymentOption(BaseModel):
class PaymentRequest(BaseModel):
id: str
message: Optional[str] = None
payment_options: List[PaymentOption]
message: str | None = None
payment_options: list[PaymentOption]
######################################## MESSAGE #######################################
@ -497,16 +497,16 @@ class DirectMessageType(Enum):
class PartialDirectMessage(BaseModel):
event_id: Optional[str] = None
event_created_at: Optional[int] = None
event_id: str | None = None
event_created_at: int | None = None
message: str
public_key: str
type: int = DirectMessageType.PLAIN_TEXT.value
incoming: bool = False
time: Optional[int] = None
time: int | None = None
@classmethod
def parse_message(cls, msg) -> Tuple[DirectMessageType, Optional[Any]]:
def parse_message(cls, msg) -> tuple[DirectMessageType, Any | None]:
try:
msg_json = json.loads(msg)
if "type" in msg_json:
@ -529,15 +529,15 @@ class DirectMessage(PartialDirectMessage):
class CustomerProfile(BaseModel):
name: Optional[str] = None
about: Optional[str] = None
name: str | None = None
about: str | None = None
class Customer(BaseModel):
merchant_id: str
public_key: str
event_created_at: Optional[int] = None
profile: Optional[CustomerProfile] = None
event_created_at: int | None = None
profile: CustomerProfile | None = None
unread_messages: int = 0
@classmethod

2616
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,42 +1,45 @@
[tool.poetry]
name = "lnbits-nostrmarket"
[project]
name = "nostrmarket"
version = "0.0.0"
requires-python = ">=3.10,<3.13"
description = "LNbits, free and open-source Lightning wallet and accounts system."
authors = ["Alan Bits <alan@lnbits.com>"]
authors = [{ name = "Alan Bits", email = "alan@lnbits.com" }]
urls = { Homepage = "https://lnbits.com", Repository = "https://github.com/lnbits/nostrmarket" }
dependencies = [ "lnbits>1" ]
[tool.poetry.dependencies]
python = "^3.10 | ^3.9"
lnbits = {version = "*", allow-prereleases = true}
[tool.poetry]
package-mode = false
[tool.poetry.group.dev.dependencies]
black = "^24.3.0"
pytest-asyncio = "^0.21.0"
pytest = "^7.3.2"
mypy = "^1.5.1"
pre-commit = "^3.2.2"
ruff = "^0.3.2"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
[dependency-groups]
dev = [
"black",
"pytest-asyncio",
"pytest",
"mypy==1.17.1",
"pre-commit",
"ruff",
"pytest-md",
"types-cffi",
]
[tool.mypy]
exclude = "(nostr/*)"
plugins = ["pydantic.mypy"]
[[tool.mypy.overrides]]
module = [
"nostr.*",
"secp256k1.*",
"embit.*",
"lnbits.*",
"lnurl.*",
"loguru.*",
"fastapi.*",
"pydantic.*",
"pyqrcode.*",
"shortuuid.*",
"httpx.*",
]
ignore_missing_imports = "True"
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
warn_untyped_fields = true
[tool.pytest.ini_options]
log_cli = false
testpaths = [

View file

@ -1,8 +1,7 @@
import asyncio
import json
from typing import List, Optional, Tuple
from lnbits.bolt11 import decode
from bolt11 import decode
from lnbits.core.crud import get_wallet
from lnbits.core.services import create_invoice, websocket_updater
from loguru import logger
@ -60,7 +59,7 @@ from .nostr.event import NostrEvent
async def create_new_order(
merchant_public_key: str, data: PartialOrder
) -> Optional[PaymentRequest]:
) -> PaymentRequest | None:
merchant = await get_merchant_by_pubkey(merchant_public_key)
assert merchant, "Cannot find merchant for order!"
@ -137,7 +136,7 @@ async def update_merchant_to_nostr(
merchant: Merchant, delete_merchant=False
) -> Merchant:
stalls = await get_stalls(merchant.id)
event: Optional[NostrEvent] = None
event: NostrEvent | None = None
for stall in stalls:
assert stall.id
products = await get_products(merchant.id, stall.id)
@ -222,7 +221,7 @@ async def notify_client_of_order_status(
async def update_products_for_order(
merchant: Merchant, order: Order
) -> Tuple[bool, str]:
) -> tuple[bool, str]:
product_ids = [i.product_id for i in order.items]
success, products, message = await compute_products_new_quantity(
merchant.id, product_ids, order.items
@ -290,9 +289,9 @@ async def send_dm(
async def compute_products_new_quantity(
merchant_id: str, product_ids: List[str], items: List[OrderItem]
) -> Tuple[bool, List[Product], str]:
products: List[Product] = await get_products_by_ids(merchant_id, product_ids)
merchant_id: str, product_ids: list[str], items: list[OrderItem]
) -> tuple[bool, list[Product], str]:
products: list[Product] = await get_products_by_ids(merchant_id, product_ids)
for p in products:
required_quantity = next(
@ -484,7 +483,7 @@ async def _handle_outgoing_dms(
async def _handle_incoming_structured_dm(
merchant: Merchant, dm: DirectMessage, json_data: dict
) -> Tuple[DirectMessageType, Optional[str]]:
) -> tuple[DirectMessageType, str | None]:
try:
if dm.type == DirectMessageType.CUSTOMER_ORDER.value and merchant.config.active:
json_resp = await _handle_new_order(

2316
uv.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,11 @@
import json
from http import HTTPStatus
from typing import List, Optional
from fastapi import Depends
from fastapi.exceptions import HTTPException
from lnbits.core.models import WalletTypeInfo
from lnbits.core.services import websocket_updater
from lnbits.decorators import (
WalletTypeInfo,
require_admin_key,
require_invoice_key,
)
@ -135,7 +134,7 @@ async def api_create_merchant(
@nostrmarket_ext.get("/api/v1/merchant")
async def api_get_merchant(
wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> Optional[Merchant]:
) -> Merchant | None:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
@ -303,7 +302,7 @@ async def api_delete_merchant_on_nostr(
@nostrmarket_ext.get("/api/v1/zone")
async def api_get_zones(
wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> List[Zone]:
) -> list[Zone]:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"
@ -503,7 +502,7 @@ async def api_get_stall(
@nostrmarket_ext.get("/api/v1/stall")
async def api_get_stalls(
pending: Optional[bool] = False,
pending: bool | None = False,
wallet: WalletTypeInfo = Depends(require_invoice_key),
):
try:
@ -527,7 +526,7 @@ async def api_get_stalls(
@nostrmarket_ext.get("/api/v1/stall/product/{stall_id}")
async def api_get_stall_products(
stall_id: str,
pending: Optional[bool] = False,
pending: bool | None = False,
wallet: WalletTypeInfo = Depends(require_invoice_key),
):
try:
@ -551,9 +550,9 @@ async def api_get_stall_products(
@nostrmarket_ext.get("/api/v1/stall/order/{stall_id}")
async def api_get_stall_orders(
stall_id: str,
paid: Optional[bool] = None,
shipped: Optional[bool] = None,
pubkey: Optional[str] = None,
paid: bool | None = None,
shipped: bool | None = None,
pubkey: str | None = None,
wallet: WalletTypeInfo = Depends(require_invoice_key),
):
try:
@ -687,7 +686,7 @@ async def api_update_product(
async def api_get_product(
product_id: str,
wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> Optional[Product]:
) -> Product | None:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"
@ -772,9 +771,9 @@ async def api_get_order(
@nostrmarket_ext.get("/api/v1/order")
async def api_get_orders(
paid: Optional[bool] = None,
shipped: Optional[bool] = None,
pubkey: Optional[str] = None,
paid: bool | None = None,
shipped: bool | None = None,
pubkey: str | None = None,
wallet: WalletTypeInfo = Depends(require_invoice_key),
):
try:
@ -860,7 +859,7 @@ async def api_update_order_status(
async def api_restore_order(
event_id: str,
wallet: WalletTypeInfo = Depends(require_admin_key),
) -> Optional[Order]:
) -> Order | None:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"
@ -987,7 +986,7 @@ async def api_reissue_order_invoice(
@nostrmarket_ext.get("/api/v1/message/{public_key}")
async def api_get_messages(
public_key: str, wallet: WalletTypeInfo = Depends(require_invoice_key)
) -> List[DirectMessage]:
) -> list[DirectMessage]:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"
@ -1043,7 +1042,7 @@ async def api_create_message(
@nostrmarket_ext.get("/api/v1/customer")
async def api_get_customers(
wallet: WalletTypeInfo = Depends(require_invoice_key),
) -> List[Customer]:
) -> list[Customer]:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"