Merge branch 'v1_update'
This commit is contained in:
commit
ef53a01bb7
12 changed files with 1185 additions and 1028 deletions
2
Makefile
2
Makefile
|
|
@ -33,7 +33,7 @@ checkeditorconfig:
|
||||||
test:
|
test:
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
DEBUG=true \
|
DEBUG=true \
|
||||||
poetry run pytest tests/unit/*.py -s
|
poetry run pytest
|
||||||
install-pre-commit-hook:
|
install-pre-commit-hook:
|
||||||
@echo "Installing pre-commit hook to git"
|
@echo "Installing pre-commit hook to git"
|
||||||
@echo "Uninstall the hook with poetry run pre-commit uninstall"
|
@echo "Uninstall the hook with poetry run pre-commit uninstall"
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
from lnbits.tasks import create_permanent_unique_task
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from lnbits.tasks import create_permanent_unique_task
|
|
||||||
from .crud import db
|
from .crud import db
|
||||||
from .tasks import handle_execution_queue, handle_nwc
|
from .tasks import handle_execution_queue, handle_nwc
|
||||||
from .views import nwcprovider_router
|
from .views import nwcprovider_router
|
||||||
|
|
@ -24,6 +24,7 @@ nwcprovider_static_files = [
|
||||||
|
|
||||||
scheduled_tasks: list[asyncio.Task] = []
|
scheduled_tasks: list[asyncio.Task] = []
|
||||||
|
|
||||||
|
|
||||||
def nwcprovider_stop():
|
def nwcprovider_stop():
|
||||||
for task in scheduled_tasks:
|
for task in scheduled_tasks:
|
||||||
try:
|
try:
|
||||||
|
|
@ -40,6 +41,7 @@ def nwcprovider_start():
|
||||||
)
|
)
|
||||||
scheduled_tasks.append(task)
|
scheduled_tasks.append(task)
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"db",
|
"db",
|
||||||
"nwcprovider_ext",
|
"nwcprovider_ext",
|
||||||
|
|
|
||||||
84
crud.py
84
crud.py
|
|
@ -5,18 +5,19 @@ from lnbits.db import Database
|
||||||
|
|
||||||
from .execution_queue import enqueue
|
from .execution_queue import enqueue
|
||||||
from .models import (
|
from .models import (
|
||||||
NWCBudget,
|
|
||||||
NWCKey,
|
|
||||||
CreateNWCKey,
|
CreateNWCKey,
|
||||||
|
DeleteNWC,
|
||||||
|
GetBudgetsNWC,
|
||||||
GetNWCKey,
|
GetNWCKey,
|
||||||
GetWalletNWC,
|
GetWalletNWC,
|
||||||
GetBudgetsNWC,
|
NWCBudget,
|
||||||
|
NWCKey,
|
||||||
TrackedSpendNWC,
|
TrackedSpendNWC,
|
||||||
DeleteNWC
|
|
||||||
)
|
)
|
||||||
|
|
||||||
db = Database("ext_nwcprovider")
|
db = Database("ext_nwcprovider")
|
||||||
|
|
||||||
|
|
||||||
async def create_nwc(data: CreateNWCKey) -> NWCKey:
|
async def create_nwc(data: CreateNWCKey) -> NWCKey:
|
||||||
nwckey_entry = NWCKey(
|
nwckey_entry = NWCKey(
|
||||||
pubkey=data.pubkey,
|
pubkey=data.pubkey,
|
||||||
|
|
@ -34,29 +35,34 @@ async def create_nwc(data: CreateNWCKey) -> NWCKey:
|
||||||
pubkey=data.pubkey,
|
pubkey=data.pubkey,
|
||||||
budget_msats=budget.budget_msats,
|
budget_msats=budget.budget_msats,
|
||||||
refresh_window=budget.refresh_window,
|
refresh_window=budget.refresh_window,
|
||||||
created_at=budget.created_at
|
created_at=budget.created_at,
|
||||||
)
|
)
|
||||||
await db.insert("nwcprovider.budgets", budget_entry)
|
await db.insert("nwcprovider.budgets", budget_entry)
|
||||||
return NWCKey(**data.dict())
|
return NWCKey(**data.dict())
|
||||||
|
|
||||||
async def delete_nwc(data:DeleteNWC) -> None:
|
|
||||||
|
async def delete_nwc(data: DeleteNWC) -> None:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"DELETE FROM nwcprovider.keys WHERE pubkey = :pubkey AND wallet = :wallet", {"pubkey": data.pubkey, "wallet": data.wallet_id}
|
"DELETE FROM nwcprovider.keys WHERE pubkey = :pubkey AND wallet = :wallet",
|
||||||
|
{"pubkey": data.pubkey, "wallet": data.wallet_id},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_wallet_nwcs(data: GetWalletNWC) -> List[NWCKey]:
|
async def get_wallet_nwcs(data: GetWalletNWC) -> List[NWCKey]:
|
||||||
return await db.fetchall(
|
return await db.fetchall(
|
||||||
"""
|
"""
|
||||||
SELECT * FROM nwcprovider.keys
|
SELECT * FROM nwcprovider.keys
|
||||||
WHERE wallet = :wallet AND (expires_at = 0 OR expires_at > :expires)
|
WHERE wallet = :wallet AND (expires_at = 0 OR expires_at > :expires)
|
||||||
""",
|
""",
|
||||||
{"wallet": data.wallet_id, "expires": int(time.time()) if not data.include_expired else -1},
|
{
|
||||||
|
"wallet": data.wallet_id,
|
||||||
|
"expires": int(time.time()) if not data.include_expired else -1,
|
||||||
|
},
|
||||||
model=NWCKey,
|
model=NWCKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get_nwc(
|
|
||||||
data: GetNWCKey
|
async def get_nwc(data: GetNWCKey) -> Optional[NWCKey]:
|
||||||
) -> Optional[NWCKey]:
|
|
||||||
# expires_at = 0 means it never expires
|
# expires_at = 0 means it never expires
|
||||||
if data.wallet_id:
|
if data.wallet_id:
|
||||||
row = await db.fetchone(
|
row = await db.fetchone(
|
||||||
|
|
@ -65,8 +71,11 @@ async def get_nwc(
|
||||||
WHERE pubkey = :pubkey AND wallet = :wallet
|
WHERE pubkey = :pubkey AND wallet = :wallet
|
||||||
AND (expires_at = 0 OR expires_at > :expires)
|
AND (expires_at = 0 OR expires_at > :expires)
|
||||||
""",
|
""",
|
||||||
{"pubkey": data.pubkey, "wallet": data.wallet_id,
|
{
|
||||||
"expires": int(time.time()) if not data.include_expired else -1},
|
"pubkey": data.pubkey,
|
||||||
|
"wallet": data.wallet_id,
|
||||||
|
"expires": int(time.time()) if not data.include_expired else -1,
|
||||||
|
},
|
||||||
NWCKey,
|
NWCKey,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -82,7 +91,10 @@ async def get_nwc(
|
||||||
SELECT * FROM nwcprovider.keys
|
SELECT * FROM nwcprovider.keys
|
||||||
WHERE pubkey = :pubkey AND (expires_at = 0 OR expires_at > :expires)
|
WHERE pubkey = :pubkey AND (expires_at = 0 OR expires_at > :expires)
|
||||||
""",
|
""",
|
||||||
{"pubkey": data.pubkey, "expires": int(time.time()) if not data.include_expired else -1},
|
{
|
||||||
|
"pubkey": data.pubkey,
|
||||||
|
"expires": int(time.time()) if not data.include_expired else -1,
|
||||||
|
},
|
||||||
NWCKey,
|
NWCKey,
|
||||||
)
|
)
|
||||||
if not row:
|
if not row:
|
||||||
|
|
@ -90,16 +102,18 @@ async def get_nwc(
|
||||||
if data.refresh_last_used:
|
if data.refresh_last_used:
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
UPDATE nwcprovider.keys SET last_used = :last_used WHERE pubkey = :pubkey
|
UPDATE nwcprovider.keys SET last_used =
|
||||||
|
:last_used WHERE pubkey = :pubkey
|
||||||
""",
|
""",
|
||||||
{"last_used":int(time.time()), "pubkey":data.pubkey},
|
{"last_used": int(time.time()), "pubkey": data.pubkey},
|
||||||
)
|
)
|
||||||
return NWCKey(**row)
|
return NWCKey(**row)
|
||||||
|
|
||||||
|
|
||||||
async def get_budgets_nwc(data: GetBudgetsNWC) -> Optional[NWCBudget]:
|
async def get_budgets_nwc(data: GetBudgetsNWC) -> Optional[NWCBudget]:
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
"SELECT * FROM nwcprovider.budgets WHERE pubkey = :pubkey", {"pubkey":data.pubkey}
|
"SELECT * FROM nwcprovider.budgets WHERE pubkey = :pubkey",
|
||||||
|
{"pubkey": data.pubkey},
|
||||||
)
|
)
|
||||||
budgets = [NWCBudget(**row) for row in rows]
|
budgets = [NWCBudget(**row) for row in rows]
|
||||||
if data.calculate_spent:
|
if data.calculate_spent:
|
||||||
|
|
@ -108,16 +122,21 @@ async def get_budgets_nwc(data: GetBudgetsNWC) -> Optional[NWCBudget]:
|
||||||
tot_spent_in_range_msats = await db.fetchone(
|
tot_spent_in_range_msats = await db.fetchone(
|
||||||
"""
|
"""
|
||||||
SELECT SUM(amount_msats) FROM nwcprovider.spent
|
SELECT SUM(amount_msats) FROM nwcprovider.spent
|
||||||
WHERE pubkey = :pubkey AND created_at >= :last_cycle AND created_at < next_cycle
|
WHERE pubkey = :pubkey AND created_at >=
|
||||||
|
:last_cycle AND created_at < next_cycle
|
||||||
""",
|
""",
|
||||||
{"pubkey":data.pubkey, "last_cycle":last_cycle, "next_cycle":next_cycle},
|
{
|
||||||
|
"pubkey": data.pubkey,
|
||||||
|
"last_cycle": last_cycle,
|
||||||
|
"next_cycle": next_cycle,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
tot_spent_in_range_msats = tot_spent_in_range_msats[0] or 0
|
tot_spent_in_range_msats = tot_spent_in_range_msats[0] or 0
|
||||||
budget.used_budget_msats = tot_spent_in_range_msats
|
budget.used_budget_msats = tot_spent_in_range_msats
|
||||||
return budgets
|
return budgets
|
||||||
|
|
||||||
|
|
||||||
async def tracked_spend_nwc(data:TrackedSpendNWC, action):
|
async def tracked_spend_nwc(data: TrackedSpendNWC, action):
|
||||||
async def r():
|
async def r():
|
||||||
created_at = int(time.time())
|
created_at = int(time.time())
|
||||||
budgets = await get_budgets_nwc(data.pubkey)
|
budgets = await get_budgets_nwc(data.pubkey)
|
||||||
|
|
@ -129,9 +148,14 @@ async def tracked_spend_nwc(data:TrackedSpendNWC, action):
|
||||||
await db.fetchone(
|
await db.fetchone(
|
||||||
"""
|
"""
|
||||||
SELECT SUM(amount_msats) FROM nwcprovider.spent
|
SELECT SUM(amount_msats) FROM nwcprovider.spent
|
||||||
WHERE pubkey = :pubkey AND created_at >= :last_cycle AND created_at < :next_cycle
|
WHERE pubkey = :pubkey AND created_at >=
|
||||||
|
:last_cycle AND created_at < :next_cycle
|
||||||
""",
|
""",
|
||||||
{"pubkey":data.pubkey, "last_cycle":last_cycle, "next_cycle":next_cycle},
|
{
|
||||||
|
"pubkey": data.pubkey,
|
||||||
|
"last_cycle": last_cycle,
|
||||||
|
"next_cycle": next_cycle,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
)[0]
|
)[0]
|
||||||
or 0
|
or 0
|
||||||
|
|
@ -147,7 +171,11 @@ async def tracked_spend_nwc(data:TrackedSpendNWC, action):
|
||||||
INSERT INTO nwcprovider.spent (pubkey, amount_msats, created_at)
|
INSERT INTO nwcprovider.spent (pubkey, amount_msats, created_at)
|
||||||
VALUES (:pubkey, :amount_msats, :created_at)
|
VALUES (:pubkey, :amount_msats, :created_at)
|
||||||
""",
|
""",
|
||||||
{"pubkey":data.pubkey, "amount_msats":data.amount_msats, "created_at":created_at},
|
{
|
||||||
|
"pubkey": data.pubkey,
|
||||||
|
"amount_msats": data.amount_msats,
|
||||||
|
"created_at": created_at,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return True, out
|
return True, out
|
||||||
|
|
||||||
|
|
@ -155,27 +183,31 @@ async def tracked_spend_nwc(data:TrackedSpendNWC, action):
|
||||||
|
|
||||||
|
|
||||||
async def get_config_nwc(key: str):
|
async def get_config_nwc(key: str):
|
||||||
row = await db.fetchone("SELECT * FROM nwcprovider.config WHERE key = :key", {"key":key})
|
row = await db.fetchone(
|
||||||
|
"SELECT * FROM nwcprovider.config WHERE key = :key", {"key": key}
|
||||||
|
)
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
return row["value"]
|
return row["value"]
|
||||||
|
|
||||||
|
|
||||||
async def set_config_nwc(key: str, value: str):
|
async def set_config_nwc(key: str, value: str):
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
DELETE FROM nwcprovider.config
|
DELETE FROM nwcprovider.config
|
||||||
WHERE key = :key
|
WHERE key = :key
|
||||||
""",
|
""",
|
||||||
{"key":key},
|
{"key": key},
|
||||||
)
|
)
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO nwcprovider.config (key, value)
|
INSERT INTO nwcprovider.config (key, value)
|
||||||
VALUES (:key, :value)
|
VALUES (:key, :value)
|
||||||
""",
|
""",
|
||||||
{"key":key, "value":value},
|
{"key": key, "value": value},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_all_config_nwc():
|
async def get_all_config_nwc():
|
||||||
rows = await db.fetchall("SELECT * FROM nwcprovider.config")
|
rows = await db.fetchall("SELECT * FROM nwcprovider.config")
|
||||||
return {row["key"]: row["value"] for row in rows}
|
return {row["key"]: row["value"] for row in rows}
|
||||||
13
models.py
13
models.py
|
|
@ -5,8 +5,10 @@ from sqlite3 import Row
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from .nwcp import NWCServiceProvider
|
from .nwcp import NWCServiceProvider
|
||||||
|
|
||||||
|
|
||||||
class NWCKey(BaseModel):
|
class NWCKey(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
wallet: str
|
wallet: str
|
||||||
|
|
@ -26,37 +28,45 @@ class NWCKey(BaseModel):
|
||||||
def from_row(cls, row: Dict[str, Any]) -> "NWCKey":
|
def from_row(cls, row: Dict[str, Any]) -> "NWCKey":
|
||||||
return cls(**row)
|
return cls(**row)
|
||||||
|
|
||||||
|
|
||||||
class GetNWCKey(BaseModel):
|
class GetNWCKey(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
wallet_id: Optional[str] = None
|
wallet_id: Optional[str] = None
|
||||||
include_expired: Optional[bool] = False
|
include_expired: Optional[bool] = False
|
||||||
refresh_last_used: Optional[bool] = False
|
refresh_last_used: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class GetNWCs(BaseModel):
|
class GetNWCs(BaseModel):
|
||||||
include_expired: bool = False
|
include_expired: bool = False
|
||||||
calculate_spent_budget: bool = False
|
calculate_spent_budget: bool = False
|
||||||
|
|
||||||
|
|
||||||
class GetWalletNWC(BaseModel):
|
class GetWalletNWC(BaseModel):
|
||||||
wallet_id: Optional[str] = None
|
wallet_id: Optional[str] = None
|
||||||
include_expired: Optional[bool] = False
|
include_expired: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class GetBudgetsNWC(BaseModel):
|
class GetBudgetsNWC(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
calculate_spent: Optional[bool] = False
|
calculate_spent: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class TrackedSpendNWC(BaseModel):
|
class TrackedSpendNWC(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
amount_msats: int
|
amount_msats: int
|
||||||
|
|
||||||
|
|
||||||
class DeleteNWC(BaseModel):
|
class DeleteNWC(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
wallet_id: Optional[str] = None
|
wallet_id: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class OnInvoicePaid(BaseModel):
|
class OnInvoicePaid(BaseModel):
|
||||||
sp: NWCServiceProvider
|
sp: NWCServiceProvider
|
||||||
pubkey: str
|
pubkey: str
|
||||||
payload: Dict
|
payload: Dict
|
||||||
|
|
||||||
|
|
||||||
class NWCBudget(BaseModel):
|
class NWCBudget(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
pubkey: str
|
pubkey: str
|
||||||
|
|
@ -105,14 +115,17 @@ class NWCRegistrationRequest(BaseModel):
|
||||||
expires_at: int
|
expires_at: int
|
||||||
budgets: List[NWCNewBudget]
|
budgets: List[NWCNewBudget]
|
||||||
|
|
||||||
|
|
||||||
class RegisterNWC(BaseModel):
|
class RegisterNWC(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
registration_data: NWCRegistrationRequest
|
registration_data: NWCRegistrationRequest
|
||||||
|
|
||||||
|
|
||||||
class NWCGetResponse(BaseModel):
|
class NWCGetResponse(BaseModel):
|
||||||
data: NWCKey
|
data: NWCKey
|
||||||
budgets: List[NWCBudget]
|
budgets: List[NWCBudget]
|
||||||
|
|
||||||
|
|
||||||
class CreateNWCKey(BaseModel):
|
class CreateNWCKey(BaseModel):
|
||||||
pubkey: str
|
pubkey: str
|
||||||
wallet_id: str
|
wallet_id: str
|
||||||
|
|
|
||||||
2
nwcp.py
2
nwcp.py
|
|
@ -76,7 +76,7 @@ class NWCServiceProvider:
|
||||||
self.request_listeners: Dict[
|
self.request_listeners: Dict[
|
||||||
str,
|
str,
|
||||||
Callable[
|
Callable[
|
||||||
["NWCServiceProvider", str, Dict],
|
[NWCServiceProvider, str, Dict],
|
||||||
Awaitable[List[Tuple[Optional[Dict], Optional[Dict], List]]],
|
Awaitable[List[Tuple[Optional[Dict], Optional[Dict], List]]],
|
||||||
],
|
],
|
||||||
] = {}
|
] = {}
|
||||||
|
|
|
||||||
2003
poetry.lock
generated
2003
poetry.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -6,8 +6,8 @@ authors = ["Riccardo Balbo <oc@rblb.it>"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10 | ^3.9"
|
python = "^3.10 | ^3.9"
|
||||||
lnbits = "*"
|
lnbits = {version = "*", allow-prereleases = true}
|
||||||
psycopg2-binary = "^2.9.9"
|
mypy = "^1.13.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = "^24.3.0"
|
black = "^24.3.0"
|
||||||
|
|
@ -16,27 +16,19 @@ pytest = "^7.3.2"
|
||||||
mypy = "^1.5.1"
|
mypy = "^1.5.1"
|
||||||
pre-commit = "^3.2.2"
|
pre-commit = "^3.2.2"
|
||||||
ruff = "^0.3.2"
|
ruff = "^0.3.2"
|
||||||
types-cffi = "^1.16.0.20240331"
|
pytest-md = "^0.2.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
exclude = "(tests/*)"
|
|
||||||
|
|
||||||
[[tool.mypy.overrides]]
|
[[tool.mypy.overrides]]
|
||||||
module = [
|
module = [
|
||||||
"lnbits.*",
|
"lnbits.*",
|
||||||
"lnurl.*",
|
|
||||||
"loguru.*",
|
"loguru.*",
|
||||||
"fastapi.*",
|
"fastapi.*",
|
||||||
"pydantic.*",
|
"pydantic.*",
|
||||||
"pyqrcode.*",
|
|
||||||
"shortuuid.*",
|
|
||||||
"httpx.*",
|
|
||||||
"websocket.*",
|
|
||||||
"secp256k1.*",
|
|
||||||
]
|
]
|
||||||
ignore_missing_imports = "True"
|
ignore_missing_imports = "True"
|
||||||
|
|
||||||
|
|
@ -52,9 +44,7 @@ line-length = 88
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
# Same as Black. + 10% rule of black
|
# Same as Black. + 10% rule of black
|
||||||
line-length = 88
|
line-length = 88
|
||||||
# exclude = [
|
|
||||||
# "nostr",
|
|
||||||
# ]
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
# Enable:
|
# Enable:
|
||||||
|
|
@ -69,7 +59,8 @@ line-length = 88
|
||||||
# RUF - ruff
|
# RUF - ruff
|
||||||
# B - bugbear
|
# B - bugbear
|
||||||
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"]
|
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"]
|
||||||
ignore = ["C901"]
|
# UP007: pyupgrade: use X | Y instead of Optional. (python3.10)
|
||||||
|
ignore = ["UP007"]
|
||||||
|
|
||||||
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
# Allow autofix for all enabled rules (when `--fix`) is provided.
|
||||||
fixable = ["ALL"]
|
fixable = ["ALL"]
|
||||||
|
|
@ -86,7 +77,7 @@ classmethod-decorators = [
|
||||||
|
|
||||||
# Ignore unused imports in __init__.py files.
|
# Ignore unused imports in __init__.py files.
|
||||||
# [tool.ruff.lint.extend-per-file-ignores]
|
# [tool.ruff.lint.extend-per-file-ignores]
|
||||||
# "__init__.py" = ["F401", "F403"]
|
# "views_api.py" = ["F401"]
|
||||||
|
|
||||||
# [tool.ruff.lint.mccabe]
|
# [tool.ruff.lint.mccabe]
|
||||||
# max-complexity = 10
|
# max-complexity = 10
|
||||||
|
|
|
||||||
20
tasks.py
20
tasks.py
|
|
@ -106,8 +106,8 @@ async def _process_invoice(
|
||||||
|
|
||||||
|
|
||||||
async def _on_pay_invoice(
|
async def _on_pay_invoice(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "pay_invoice", data.payload)
|
error = await _check(nwc, "pay_invoice", data.payload)
|
||||||
if error:
|
if error:
|
||||||
|
|
@ -136,7 +136,7 @@ async def _on_pay_invoice(
|
||||||
|
|
||||||
|
|
||||||
async def _on_multi_pay_invoice(
|
async def _on_multi_pay_invoice(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "multi_pay_invoice", data.payload)
|
error = await _check(nwc, "multi_pay_invoice", data.payload)
|
||||||
|
|
@ -161,7 +161,7 @@ async def _on_multi_pay_invoice(
|
||||||
invoice_data = bolt11_decode(invoice)
|
invoice_data = bolt11_decode(invoice)
|
||||||
amount_msats = int(invoice_data.amount_msat or 0)
|
amount_msats = int(invoice_data.amount_msat or 0)
|
||||||
res = await _process_invoice(
|
res = await _process_invoice(
|
||||||
nwc.wallet, pubkey, invoice, amount_msats, invoice_data.description
|
nwc.wallet, data.pubkey, invoice, amount_msats, invoice_data.description
|
||||||
)
|
)
|
||||||
error = res.get("error")
|
error = res.get("error")
|
||||||
if error:
|
if error:
|
||||||
|
|
@ -182,7 +182,7 @@ async def _on_multi_pay_invoice(
|
||||||
|
|
||||||
|
|
||||||
async def _on_make_invoice(
|
async def _on_make_invoice(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "make_invoice", data.payload)
|
error = await _check(nwc, "make_invoice", data.payload)
|
||||||
|
|
@ -234,7 +234,7 @@ async def _on_make_invoice(
|
||||||
|
|
||||||
|
|
||||||
async def _on_lookup_invoice(
|
async def _on_lookup_invoice(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "lookup_invoice", data.payload)
|
error = await _check(nwc, "lookup_invoice", data.payload)
|
||||||
|
|
@ -281,7 +281,7 @@ async def _on_lookup_invoice(
|
||||||
|
|
||||||
|
|
||||||
async def _on_list_transactions(
|
async def _on_list_transactions(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "list_transactions", data.payload)
|
error = await _check(nwc, "list_transactions", data.payload)
|
||||||
|
|
@ -337,7 +337,7 @@ async def _on_list_transactions(
|
||||||
|
|
||||||
|
|
||||||
async def _on_get_balance(
|
async def _on_get_balance(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "get_balance", data.payload)
|
error = await _check(nwc, "get_balance", data.payload)
|
||||||
|
|
@ -355,7 +355,7 @@ async def _on_get_balance(
|
||||||
|
|
||||||
|
|
||||||
async def _on_get_info(
|
async def _on_get_info(
|
||||||
data:OnInvoicePaid
|
data: OnInvoicePaid,
|
||||||
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
) -> List[Tuple[Optional[Dict], Optional[Dict], List]]:
|
||||||
nwc = await get_nwc(data.pubkey, None, False, True)
|
nwc = await get_nwc(data.pubkey, None, False, True)
|
||||||
error = await _check(nwc, "get_info", data.payload)
|
error = await _check(nwc, "get_info", data.payload)
|
||||||
|
|
@ -363,7 +363,7 @@ async def _on_get_info(
|
||||||
return [(None, error, [])]
|
return [(None, error, [])]
|
||||||
if not nwc:
|
if not nwc:
|
||||||
raise Exception("Pubkey has no associated wallet")
|
raise Exception("Pubkey has no associated wallet")
|
||||||
sp_methods = sp.get_supported_methods()
|
sp_methods = data.sp.get_supported_methods()
|
||||||
permissions = nwc.get_permissions()
|
permissions = nwc.get_permissions()
|
||||||
# Filter only methods supported by the extension and allowed by the permissions
|
# Filter only methods supported by the extension and allowed by the permissions
|
||||||
account_methods = []
|
account_methods = []
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@
|
||||||
</div>
|
</div>
|
||||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||||
<script>
|
<script>
|
||||||
window.app = Vue.createApp({
|
window.app = Vue.createApp({
|
||||||
el: '#vue',
|
el: "#vue",
|
||||||
mixins: [windowMixin],
|
mixins: [windowMixin],
|
||||||
delimiters: ["${", "}"],
|
delimiters: ["${", "}"],
|
||||||
data: function () {
|
data: function () {
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,8 @@
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<h6 class="text-subtitle1 q-my-none">NWC Service provider</h6>
|
<h6 class="text-subtitle1 q-my-none">NWC Service provider</h6>
|
||||||
<p>
|
<p>
|
||||||
Nostr Wallet Connect (NWC) is an open protocol to connect lightning wallets to apps
|
Nostr Wallet Connect (NWC) is an open protocol to connect lightning
|
||||||
|
wallets to apps
|
||||||
</p>
|
</p>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="q-pa-none">
|
<q-card-section class="q-pa-none">
|
||||||
|
|
@ -407,8 +408,8 @@
|
||||||
window.NobleSecp256k1 = NobleSecp256k1;
|
window.NobleSecp256k1 = NobleSecp256k1;
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
window.app = Vue.createApp({
|
window.app = Vue.createApp({
|
||||||
el: '#vue',
|
el: "#vue",
|
||||||
mixins: [windowMixin],
|
mixins: [windowMixin],
|
||||||
delimiters: ["${", "}"],
|
delimiters: ["${", "}"],
|
||||||
data: function () {
|
data: function () {
|
||||||
|
|
|
||||||
31
views_api.py
31
views_api.py
|
|
@ -18,13 +18,13 @@ from .crud import (
|
||||||
set_config_nwc,
|
set_config_nwc,
|
||||||
)
|
)
|
||||||
from .models import (
|
from .models import (
|
||||||
NWCGetResponse,
|
DeleteNWC,
|
||||||
RegisterNWC,
|
|
||||||
GetWalletNWC,
|
|
||||||
GetBudgetsNWC,
|
GetBudgetsNWC,
|
||||||
GetNWCKey,
|
GetNWCKey,
|
||||||
GetNWCs,
|
GetNWCs,
|
||||||
DeleteNWC
|
GetWalletNWC,
|
||||||
|
NWCGetResponse,
|
||||||
|
RegisterNWC,
|
||||||
)
|
)
|
||||||
from .permission import nwc_permissions
|
from .permission import nwc_permissions
|
||||||
|
|
||||||
|
|
@ -50,16 +50,14 @@ async def api_get_nwcs(
|
||||||
|
|
||||||
wallet_id = wallet.wallet.id
|
wallet_id = wallet.wallet.id
|
||||||
wallet_nwcs = GetWalletNWC(
|
wallet_nwcs = GetWalletNWC(
|
||||||
wallet_id=wallet_id,
|
wallet_id=wallet_id, include_expired=data.include_expired
|
||||||
include_expired=data.include_expired
|
)
|
||||||
)
|
|
||||||
nwcs = await get_wallet_nwcs(wallet_nwcs)
|
nwcs = await get_wallet_nwcs(wallet_nwcs)
|
||||||
out = []
|
out = []
|
||||||
for nwc in nwcs:
|
for nwc in nwcs:
|
||||||
budgets_nwc = GetBudgetsNWC(
|
budgets_nwc = GetBudgetsNWC(
|
||||||
pubkey=nwc.pubkey,
|
pubkey=nwc.pubkey, calculate_spent=data.calculate_spent_budget
|
||||||
calculate_spent=data.calculate_spent_budget
|
)
|
||||||
)
|
|
||||||
budgets = await get_budgets_nwc(budgets_nwc)
|
budgets = await get_budgets_nwc(budgets_nwc)
|
||||||
res = NWCGetResponse(data=nwc, budgets=budgets)
|
res = NWCGetResponse(data=nwc, budgets=budgets)
|
||||||
out.append(res)
|
out.append(res)
|
||||||
|
|
@ -71,9 +69,8 @@ async def api_get_nwcs(
|
||||||
"/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK, response_model=NWCGetResponse
|
"/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK, response_model=NWCGetResponse
|
||||||
)
|
)
|
||||||
async def api_get_nwc(
|
async def api_get_nwc(
|
||||||
data:GetNWCKey,
|
data: GetNWCKey, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key)
|
) -> NWCGetResponse:
|
||||||
) -> NWCGetResponse:
|
|
||||||
wallet_id = wallet.wallet.id
|
wallet_id = wallet.wallet.id
|
||||||
nwc = await get_nwc(data.pubkey, wallet_id, data.include_expired)
|
nwc = await get_nwc(data.pubkey, wallet_id, data.include_expired)
|
||||||
if not nwc:
|
if not nwc:
|
||||||
|
|
@ -126,7 +123,7 @@ async def api_get_pairing_url(req: Request, secret: str) -> str:
|
||||||
response_model=NWCGetResponse,
|
response_model=NWCGetResponse,
|
||||||
)
|
)
|
||||||
async def api_register_nwc(
|
async def api_register_nwc(
|
||||||
data:RegisterNWC, # Use the Pydantic model here
|
data: RegisterNWC, # Use the Pydantic model here
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
):
|
):
|
||||||
wallet_id = wallet.wallet.id
|
wallet_id = wallet.wallet.id
|
||||||
|
|
@ -146,11 +143,13 @@ async def api_register_nwc(
|
||||||
# Delete a nwc key
|
# Delete a nwc key
|
||||||
@nwcprovider_api_router.delete("/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK)
|
@nwcprovider_api_router.delete("/api/v1/nwc/{pubkey}", status_code=HTTPStatus.OK)
|
||||||
async def api_delete_nwc(
|
async def api_delete_nwc(
|
||||||
data:DeleteNWC, wallet: WalletTypeInfo = Depends(require_admin_key)
|
data: DeleteNWC, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||||
):
|
):
|
||||||
wallet_id = wallet.wallet.id
|
wallet_id = wallet.wallet.id
|
||||||
await delete_nwc(data.pubkey, wallet_id)
|
await delete_nwc(data.pubkey, wallet_id)
|
||||||
return JSONResponse(content={"message": f"NWC key {data.pubkey} deleted successfully."})
|
return JSONResponse(
|
||||||
|
content={"message": f"NWC key {data.pubkey} deleted successfully."}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Get config
|
# Get config
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue