This commit is contained in:
dni ⚡
2024-10-10 09:07:49 +02:00
parent 03b1a4f729
commit ba843b3df4
6 changed files with 46 additions and 24 deletions
+11 -7
View File
@@ -311,8 +311,8 @@ async def get_installed_extensions(
active: Optional[bool] = None, active: Optional[bool] = None,
conn: Optional[Connection] = None, conn: Optional[Connection] = None,
) -> list[InstallableExtension]: ) -> list[InstallableExtension]:
where = "WHERE active = :active" if active else "" where = "WHERE active = :active" if active is not None else ""
values = {"active": active} if active else {} values = {"active": active} if active is not None else {}
all_extensions = await (conn or db).fetchall( all_extensions = await (conn or db).fetchall(
f"SELECT * FROM installed_extensions {where}", f"SELECT * FROM installed_extensions {where}",
values, values,
@@ -503,8 +503,9 @@ async def get_wallet(
) -> Optional[Wallet]: ) -> Optional[Wallet]:
return await (conn or db).fetchone( return await (conn or db).fetchone(
""" """
SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) SELECT *, COALESCE((
AS balance_msat FROM wallets WHERE id = :wallet SELECT balance FROM balances WHERE wallet_id = wallets.id
), 0) AS balance_msat FROM wallets WHERE id = :wallet
""", """,
{"wallet": wallet_id}, {"wallet": wallet_id},
Wallet, Wallet,
@@ -514,8 +515,9 @@ async def get_wallet(
async def get_wallets(user_id: str, conn: Optional[Connection] = None) -> list[Wallet]: async def get_wallets(user_id: str, conn: Optional[Connection] = None) -> list[Wallet]:
return await (conn or db).fetchall( return await (conn or db).fetchall(
""" """
SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) SELECT *, COALESCE((
AS balance_msat FROM wallets WHERE "user" = :user SELECT balance FROM balances WHERE wallet_id = wallets.id
), 0) AS balance_msat FROM wallets WHERE "user" = :user
""", """,
{"user": user_id}, {"user": user_id},
Wallet, Wallet,
@@ -528,7 +530,9 @@ async def get_wallet_for_key(
) -> Optional[Wallet]: ) -> Optional[Wallet]:
return await (conn or db).fetchone( return await (conn or db).fetchone(
""" """
SELECT *, COALESCE((SELECT balance FROM balances WHERE wallet = wallets.id), 0) SELECT *, COALESCE((
SELECT balance FROM balances WHERE wallet_id = wallets.id
), 0)
AS balance_msat FROM wallets AS balance_msat FROM wallets
WHERE (adminkey = :key OR inkey = :key) AND deleted = false WHERE (adminkey = :key OR inkey = :key) AND deleted = false
""", """,
+12 -4
View File
@@ -35,10 +35,15 @@ class BaseWallet(BaseModel):
balance_msat: int balance_msat: int
class Wallet(BaseWallet): class Wallet(BaseModel):
id: str
user: str user: str
name: str
adminkey: str
inkey: str
balance_msat: int
currency: Optional[str] currency: Optional[str]
deleted: bool deleted: bool = False
created_at: Optional[int] = None created_at: Optional[int] = None
updated_at: Optional[int] = None updated_at: Optional[int] = None
@@ -109,8 +114,6 @@ class Account(BaseModel):
password_hash: Optional[str] = None password_hash: Optional[str] = None
email: Optional[str] = None email: Optional[str] = None
balance_msat: Optional[int] = 0 balance_msat: Optional[int] = 0
transaction_count: Optional[int] = 0
wallet_count: Optional[int] = 0
last_payment: Optional[datetime] = None last_payment: Optional[datetime] = None
extra: Optional[UserExtra] = None extra: Optional[UserExtra] = None
created_at: datetime = datetime.now() created_at: datetime = datetime.now()
@@ -138,6 +141,11 @@ class Account(BaseModel):
return pwd_context.verify(password, self.password_hash) return pwd_context.verify(password, self.password_hash)
class AccountOverview(Account):
transaction_count: Optional[int] = 0
wallet_count: Optional[int] = 0
class AccountFilters(FilterModel): class AccountFilters(FilterModel):
__search_fields__ = ["id", "email", "username"] __search_fields__ = ["id", "email", "username"]
__sort_fields__ = [ __sort_fields__ = [
+9 -7
View File
@@ -159,7 +159,7 @@ async def extensions(request: Request, user: User = Depends(check_user_exists)):
request, request,
"core/extensions.html", "core/extensions.html",
{ {
"user": user.dict(), "user": user.json(),
"extensions": extensions, "extensions": extensions,
}, },
) )
@@ -200,8 +200,8 @@ async def wallet(
request, request,
"core/wallet.html", "core/wallet.html",
{ {
"user": user.dict(), "user": user.json(),
"wallet": wallet.dict(), "wallet": wallet.json(),
"currencies": allowed_currencies(), "currencies": allowed_currencies(),
"service_fee": settings.lnbits_service_fee, "service_fee": settings.lnbits_service_fee,
"service_fee_max": settings.lnbits_service_fee_max, "service_fee_max": settings.lnbits_service_fee_max,
@@ -224,7 +224,9 @@ async def account(
return template_renderer().TemplateResponse( return template_renderer().TemplateResponse(
request, request,
"core/account.html", "core/account.html",
{"user": user.dict()}, {
"user": user.json(),
},
) )
@@ -334,7 +336,7 @@ async def node(request: Request, user: User = Depends(check_admin)):
request, request,
"node/index.html", "node/index.html",
{ {
"user": user.dict(), "user": user.json(),
"settings": settings.dict(), "settings": settings.dict(),
"balance": balance, "balance": balance,
"wallets": user.wallets[0].dict(), "wallets": user.wallets[0].dict(),
@@ -372,7 +374,7 @@ async def admin_index(request: Request, user: User = Depends(check_admin)):
request, request,
"admin/index.html", "admin/index.html",
{ {
"user": user.dict(), "user": user.json(),
"settings": settings.dict(), "settings": settings.dict(),
"balance": balance, "balance": balance,
"currencies": list(currencies.keys()), "currencies": list(currencies.keys()),
@@ -389,7 +391,7 @@ async def users_index(request: Request, user: User = Depends(check_admin)):
"users/index.html", "users/index.html",
{ {
"request": request, "request": request,
"user": user.dict(), "user": user.json(),
"settings": settings.dict(), "settings": settings.dict(),
"currencies": list(currencies.keys()), "currencies": list(currencies.keys()),
}, },
+5 -1
View File
@@ -624,7 +624,11 @@ def dict_to_model(_row: dict, model: type[TModel]) -> TModel:
if key not in model.__fields__: if key not in model.__fields__:
logger.warning(f"Converting {key} to model `{model}`.") logger.warning(f"Converting {key} to model `{model}`.")
continue continue
if not value:
continue
type_ = model.__fields__[key].type_ type_ = model.__fields__[key].type_
if issubclass(type_, BaseModel): if issubclass(type_, BaseModel) and value is not None:
_dict[key] = type_.construct(**json.loads(value)) _dict[key] = type_.construct(**json.loads(value))
continue
_dict[key] = value
return model.construct(**_dict) return model.construct(**_dict)
+7 -3
View File
@@ -20,6 +20,7 @@ from lnbits.core.crud import (
) )
from lnbits.core.models import ( from lnbits.core.models import (
AccessTokenPayload, AccessTokenPayload,
Account,
KeyType, KeyType,
SimpleStatus, SimpleStatus,
User, User,
@@ -144,7 +145,10 @@ async def check_user_exists(
else: else:
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Missing user ID or access token.") raise HTTPException(HTTPStatus.UNAUTHORIZED, "Missing user ID or access token.")
if not account or not settings.is_user_allowed(account.id): if not account:
raise HTTPException(HTTPStatus.UNAUTHORIZED, "User not found.")
if not settings.is_user_allowed(account.id):
raise HTTPException(HTTPStatus.UNAUTHORIZED, "User not allowed.") raise HTTPException(HTTPStatus.UNAUTHORIZED, "User not allowed.")
user = await get_user(account) user = await get_user(account)
@@ -258,7 +262,7 @@ async def _check_user_extension_access(user_id: str, current_path: str):
) )
async def _get_account_from_token(access_token) -> Optional[User]: async def _get_account_from_token(access_token) -> Optional[Account]:
try: try:
payload: dict = jwt.decode(access_token, settings.auth_secret_key, ["HS256"]) payload: dict = jwt.decode(access_token, settings.auth_secret_key, ["HS256"])
user = await _get_user_from_jwt_payload(payload) user = await _get_user_from_jwt_payload(payload)
@@ -278,7 +282,7 @@ async def _get_account_from_token(access_token) -> Optional[User]:
raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid access token.") from exc raise HTTPException(HTTPStatus.UNAUTHORIZED, "Invalid access token.") from exc
async def _get_user_from_jwt_payload(payload) -> Optional[User]: async def _get_user_from_jwt_payload(payload) -> Optional[Account]:
if "sub" in payload and payload.get("sub"): if "sub" in payload and payload.get("sub"):
return await get_account_by_username(str(payload.get("sub"))) return await get_account_by_username(str(payload.get("sub")))
if "usr" in payload and payload.get("usr"): if "usr" in payload and payload.get("usr"):
+2 -2
View File
@@ -5,10 +5,10 @@
window.currencies = {{ currencies | tojson | safe }}; window.currencies = {{ currencies | tojson | safe }};
{% endif %} {% endif %}
{% if user %} {% if user %}
window.user = {{ user | tojson | safe }}; window.user = JSON.parse({{ user | tojson | safe }});
{% endif %} {% endif %}
{% if wallet %} {% if wallet %}
window.wallet = {{ wallet | tojson | safe }}; window.wallet = JSON.parse({{ wallet | tojson | safe }});
{% endif %} {% endif %}
</script> </script>
{%- endmacro %} {%- endmacro %}