code improvements, bugfixes

This commit is contained in:
dni ⚡
2022-12-05 15:43:26 +01:00
parent 12b0ec138d
commit 35920bae48
6 changed files with 140 additions and 128 deletions

View File

@@ -2,7 +2,7 @@ from typing import Optional
from lnbits.core.crud import create_payment from lnbits.core.crud import create_payment
from lnbits.helpers import urlsafe_short_hash from lnbits.helpers import urlsafe_short_hash
from lnbits.settings import Settings, read_only_variables, settings from lnbits.settings import read_only_variables, settings
from lnbits.tasks import internal_invoice_queue from lnbits.tasks import internal_invoice_queue
from . import db from . import db
@@ -27,21 +27,20 @@ async def update_wallet_balance(wallet_id: str, amount: int):
return payment return payment
async def get_settings() -> AdminSettings: async def get_admin_settings() -> AdminSettings:
row = await db.fetchone("SELECT * FROM admin.settings") row = await db.fetchone("SELECT * FROM admin.settings")
all_settings = Settings(**row) admin_settings = AdminSettings(**row, lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources)
settings = AdminSettings() for key, _ in row.items():
for key, value in row.items(): if hasattr(admin_settings, key):
if hasattr(settings, key): setattr(admin_settings, key, getattr(settings, key))
setattr(settings, key, getattr(all_settings, key)) return admin_settings
return settings
async def update_settings(data: UpdateSettings) -> Optional[Settings]: async def update_admin_settings(data: UpdateSettings) -> Optional[AdminSettings]:
fields = [] fields = []
for key, value in data.dict(exclude_none=True).items(): for key, value in data.items():
setattr(settings, key, value)
if not key in read_only_variables: if not key in read_only_variables:
setattr(settings, key, value)
if type(value) == list: if type(value) == list:
joined = ",".join(value) joined = ",".join(value)
fields.append(f"{key} = '{joined}'") fields.append(f"{key} = '{joined}'")
@@ -52,13 +51,12 @@ async def update_settings(data: UpdateSettings) -> Optional[Settings]:
if type(value) == str: if type(value) == str:
value = value.replace("'", "") value = value.replace("'", "")
fields.append(f"{key} = '{value}'") fields.append(f"{key} = '{value}'")
q = ", ".join(fields) q = ", ".join(fields)
await db.execute(f"UPDATE admin.settings SET {q}") await db.execute(f"UPDATE admin.settings SET {q}")
row = await db.fetchone("SELECT * FROM admin.settings") row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved" assert row, "Newly updated settings couldn't be retrieved"
return Settings(**row) if row else None return AdminSettings(**row) if row else None
async def delete_settings(): async def delete_admin_settings():
await db.execute("DELETE FROM admin.settings") await db.execute("DELETE FROM admin.settings")

View File

@@ -2,20 +2,8 @@ async def m001_create_admin_settings_table(db):
await db.execute( await db.execute(
""" """
CREATE TABLE IF NOT EXISTS admin.settings ( CREATE TABLE IF NOT EXISTS admin.settings (
lnbits_admin_ui TEXT,
debug TEXT,
host TEXT,
port INTEGER,
forwarded_allow_ips TEXT,
lnbits_saas_instance_id TEXT,
lnbits_saas_callback TEXT,
lnbits_saas_secret TEXT,
lnbits_path TEXT,
lnbits_commit TEXT,
lnbits_admin_users TEXT, lnbits_admin_users TEXT,
lnbits_allowed_users TEXT, lnbits_allowed_users TEXT,
lnbits_allowed_funding_sources TEXT,
lnbits_admin_extensions TEXT,
lnbits_disabled_extensions TEXT, lnbits_disabled_extensions TEXT,
lnbits_site_title TEXT, lnbits_site_title TEXT,
lnbits_site_tagline TEXT, lnbits_site_tagline TEXT,
@@ -35,9 +23,9 @@ async def m001_create_admin_settings_table(db):
lnbits_hide_api TEXT, lnbits_hide_api TEXT,
lnbits_denomination TEXT, lnbits_denomination TEXT,
lnbits_backend_wallet_class TEXT, lnbits_backend_wallet_class TEXT,
fake_wallet_secret TEXT,
lnbits_endpoint TEXT, lnbits_endpoint TEXT,
lnbits_key TEXT, lnbits_key TEXT,
fake_wallet_secret TEXT,
cliche_endpoint TEXT, cliche_endpoint TEXT,
corelightning_rpc TEXT, corelightning_rpc TEXT,
eclair_url TEXT, eclair_url TEXT,

View File

@@ -1,16 +1,28 @@
from typing import List, Optional from typing import List, Optional
from fastapi import Query from fastapi import Query
from pydantic import BaseModel from pydantic import BaseModel, validator
class UpdateSettings(BaseModel): class UpdateSettings(BaseModel):
@validator(
"lnbits_admin_users",
"lnbits_allowed_users",
"lnbits_theme_options",
"lnbits_disabled_extensions",
pre=True,
)
def validate(cls, val):
if type(val) == str:
val = val.split(",") if val else []
return val
lnbits_backend_wallet_class: str = Query(None) lnbits_backend_wallet_class: str = Query(None)
lnbits_admin_users: List[str] = Query(None) lnbits_admin_users: List[str] = Query(None)
lnbits_allowed_users: List[str] = Query(None) lnbits_allowed_users: List[str] = Query(None)
lnbits_admin_ext: List[str] = Query(None) lnbits_disabled_extensions: List[str] = Query(None)
lnbits_disabled_ext: List[str] = Query(None) lnbits_theme_options: List[str] = Query(None)
lnbits_funding_source: str = Query(None)
lnbits_force_https: bool = Query(None) lnbits_force_https: bool = Query(None)
lnbits_reserve_fee_min: int = Query(None, ge=0) lnbits_reserve_fee_min: int = Query(None, ge=0)
lnbits_reserve_fee_percent: float = Query(None, ge=0) lnbits_reserve_fee_percent: float = Query(None, ge=0)
@@ -21,7 +33,6 @@ class UpdateSettings(BaseModel):
lnbits_site_description: str = Query(None) lnbits_site_description: str = Query(None)
lnbits_default_wallet_name: str = Query(None) lnbits_default_wallet_name: str = Query(None)
lnbits_denomination: str = Query(None) lnbits_denomination: str = Query(None)
lnbits_theme: str = Query(None)
lnbits_custom_logo: str = Query(None) lnbits_custom_logo: str = Query(None)
lnbits_ad_space: str = Query(None) lnbits_ad_space: str = Query(None)
lnbits_ad_space_title: str = Query(None) lnbits_ad_space_title: str = Query(None)

View File

@@ -1,6 +1,3 @@
from email.policy import default
from os import getenv
from fastapi import Request from fastapi import Request
from fastapi.params import Depends from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
@@ -8,7 +5,6 @@ from starlette.responses import HTMLResponse
from lnbits.core.models import User from lnbits.core.models import User
from lnbits.decorators import check_admin from lnbits.decorators import check_admin
from lnbits.requestvars import g
from lnbits.settings import get_wallet_class, settings from lnbits.settings import get_wallet_class, settings
from . import admin_ext, admin_renderer from . import admin_ext, admin_renderer
@@ -19,7 +15,7 @@ templates = Jinja2Templates(directory="templates")
@admin_ext.get("/", response_class=HTMLResponse) @admin_ext.get("/", response_class=HTMLResponse)
async def index(request: Request, user: User = Depends(check_admin)): # type: ignore async def index(request: Request, user: User = Depends(check_admin)): # type: ignore
WALLET = get_wallet_class() WALLET = get_wallet_class()
error, balance = await WALLET.status() _, balance = await WALLET.status()
return admin_renderer().TemplateResponse( return admin_renderer().TemplateResponse(
"admin/index.html", "admin/index.html",

View File

@@ -7,10 +7,10 @@ from starlette.exceptions import HTTPException
from lnbits.core.crud import get_wallet from lnbits.core.crud import get_wallet
from lnbits.decorators import check_admin from lnbits.decorators import check_admin
from lnbits.extensions.admin import admin_ext from lnbits.extensions.admin import admin_ext
from lnbits.extensions.admin.models import UpdateSettings from lnbits.extensions.admin.models import AdminSettings, UpdateSettings
from lnbits.server import server_restart from lnbits.server import server_restart
from .crud import delete_settings, get_settings, update_settings, update_wallet_balance from .crud import delete_admin_settings, get_admin_settings, update_admin_settings, update_wallet_balance
@admin_ext.get( @admin_ext.get(
@@ -22,8 +22,8 @@ async def api_restart_server() -> dict[str, str]:
@admin_ext.get("/api/v1/settings/", dependencies=[Depends(check_admin)]) @admin_ext.get("/api/v1/settings/", dependencies=[Depends(check_admin)])
async def api_get_settings() -> UpdateSettings: async def api_get_settings() -> AdminSettings:
return await get_settings() return await get_admin_settings()
@admin_ext.put( @admin_ext.put(
@@ -50,7 +50,7 @@ async def api_update_balance(
async def api_update_settings( async def api_update_settings(
data: UpdateSettings = Body(...), data: UpdateSettings = Body(...),
): ):
settings = await update_settings(data) settings = await update_admin_settings(data)
if settings: if settings:
return {"status": "Success", "settings": settings.dict()} return {"status": "Success", "settings": settings.dict()}
@@ -59,5 +59,5 @@ async def api_update_settings(
"/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)] "/api/v1/settings/", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)]
) )
async def api_delete_settings() -> dict[str, str]: async def api_delete_settings() -> dict[str, str]:
await delete_settings() await delete_admin_settings()
return {"status": "Success"} return {"status": "Success"}

View File

@@ -10,6 +10,7 @@ from loguru import logger
from pydantic import BaseSettings, Field, validator from pydantic import BaseSettings, Field, validator
def list_parse_fallback(v): def list_parse_fallback(v):
try: try:
return json.loads(v) return json.loads(v)
@@ -24,6 +25,13 @@ def list_parse_fallback(v):
read_only_variables = [ read_only_variables = [
"host", "host",
"port", "port",
"debug",
"lnbits_allowed_funding_sources",
"lnbits_admin_extensions",
"lnbits_saas_secret",
"lnbits_saas_callback",
"lnbits_saas_instance_id",
"lnbits_admin_ui",
"lnbits_commit", "lnbits_commit",
"lnbits_path", "lnbits_path",
"forwarded_allow_ips", "forwarded_allow_ips",
@@ -178,6 +186,7 @@ except:
settings.lnbits_commit = "docker" settings.lnbits_commit = "docker"
# printing enviroment variable for debugging
if not settings.lnbits_admin_ui: if not settings.lnbits_admin_ui:
logger.debug(f"Enviroment Settings:") logger.debug(f"Enviroment Settings:")
for key, value in settings.dict(exclude_none=True).items(): for key, value in settings.dict(exclude_none=True).items():
@@ -198,13 +207,61 @@ async def check_admin_settings():
raise raise
async with ext_db.connect() as db: async with ext_db.connect() as db:
try:
row = await db.fetchone("SELECT * FROM admin.settings") row = await db.fetchone("SELECT * FROM admin.settings")
# create new settings if table is empty
if not row or len(row) == 0: if not row or len(row) == 0:
logger.warning( logger.warning(
"admin.settings empty. inserting new settings and creating admin account" "admin.settings empty. inserting new settings and creating admin account"
) )
row = await create_admin_settings(db)
# setting settings from database into memory
from lnbits.extensions.admin.models import AdminSettings
sets = AdminSettings(**row, lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources)
for key, value in sets.dict().items():
if not key in read_only_variables:
try:
setattr(settings, key, value)
except:
logger.error(
f"error overriding setting: {key}, value: {value}"
)
# printing settings for debugging
logger.debug(f"Admin settings:")
for key, value in settings.dict(exclude_none=True).items():
logger.debug(f"{key}: {value}")
http = "https" if settings.lnbits_force_https else "http"
user = settings.lnbits_admin_users[0]
admin_url = (
f"{http}://{settings.host}:{settings.port}/wallet?usr={user}"
)
logger.warning(f"✔️ Access admin user account at: {admin_url}")
# callback for saas
if (
settings.lnbits_saas_callback
and settings.lnbits_saas_secret
and settings.lnbits_saas_instance_id
):
send_admin_user_to_saas(user)
wallets_module = importlib.import_module("lnbits.wallets")
FAKE_WALLET = getattr(wallets_module, "FakeWallet")()
def get_wallet_class():
wallet_class = getattr(wallets_module, settings.lnbits_backend_wallet_class)
return wallet_class()
async def create_admin_settings(db):
# if not imported here, circular import error
from lnbits.core.crud import create_account from lnbits.core.crud import create_account
account = await create_account() account = await create_account()
@@ -212,6 +269,7 @@ async def check_admin_settings():
keys = [] keys = []
values = "" values = ""
for key, value in settings.dict(exclude_none=True).items(): for key, value in settings.dict(exclude_none=True).items():
if not key in read_only_variables:
keys.append(key) keys.append(key)
if type(value) == list: if type(value) == list:
joined = ",".join(value) joined = ",".join(value)
@@ -231,38 +289,12 @@ async def check_admin_settings():
logger.warning( logger.warning(
"initialized admin.settings from enviroment variables." "initialized admin.settings from enviroment variables."
) )
row = await db.fetchone("SELECT * FROM admin.settings") row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved" assert row, "Newly updated settings couldn't be retrieved"
return row
admin = Settings(**row)
for key, value in admin.dict(exclude_none=True).items(): def send_admin_user_to_saas(user):
if not key in read_only_variables:
try:
setattr(settings, key, value)
except:
logger.error(
f"error overriding setting: {key}, value: {value}"
)
logger.debug(f"Admin settings:")
for key, value in settings.dict(exclude_none=True).items():
logger.debug(f"{key}: {value}")
http = "https" if settings.lnbits_force_https else "http"
user = settings.lnbits_admin_users[0]
admin_url = (
f"{http}://{settings.host}:{settings.port}/wallet?usr={user}"
)
logger.warning(f"✔️ Access admin user account at: {admin_url}")
if (
settings.lnbits_saas_callback
and settings.lnbits_saas_secret
and settings.lnbits_saas_instance_id
):
with httpx.Client() as client: with httpx.Client() as client:
headers = { headers = {
"Content-Type": "application/json; charset=utf-8", "Content-Type": "application/json; charset=utf-8",
@@ -283,16 +315,3 @@ async def check_admin_settings():
logger.error( logger.error(
f"error sending admin user to saas: {settings.lnbits_saas_callback}" f"error sending admin user to saas: {settings.lnbits_saas_callback}"
) )
except:
logger.error("admin.settings tables does not exist.")
raise
wallets_module = importlib.import_module("lnbits.wallets")
FAKE_WALLET = getattr(wallets_module, "FakeWallet")()
def get_wallet_class():
wallet_class = getattr(wallets_module, settings.lnbits_backend_wallet_class)
return wallet_class()