refactor from settings.py into admin crud, but broke frontend

formatting
This commit is contained in:
dni ⚡
2022-12-06 10:58:59 +01:00
parent c56a31e6f5
commit d2cd972663
6 changed files with 108 additions and 110 deletions

View File

@@ -4,7 +4,6 @@ import logging
import signal import signal
import sys import sys
import traceback import traceback
import warnings
from http import HTTPStatus from http import HTTPStatus
from fastapi import FastAPI, Request from fastapi import FastAPI, Request

View File

@@ -1,6 +1,6 @@
from typing import Optional from typing import Optional
from lnbits.core.crud import create_payment from lnbits.core.crud import create_account, create_payment
from lnbits.helpers import urlsafe_short_hash from lnbits.helpers import urlsafe_short_hash
from lnbits.settings import readonly_variables, settings from lnbits.settings import readonly_variables, settings
from lnbits.tasks import internal_invoice_queue from lnbits.tasks import internal_invoice_queue
@@ -11,7 +11,6 @@ from .models import AdminSettings, UpdateSettings
async def update_wallet_balance(wallet_id: str, amount: int): async def update_wallet_balance(wallet_id: str, amount: int):
internal_id = f"internal_{urlsafe_short_hash()}" internal_id = f"internal_{urlsafe_short_hash()}"
payment = await create_payment( payment = await create_payment(
wallet_id=wallet_id, wallet_id=wallet_id,
checking_id=internal_id, checking_id=internal_id,
@@ -23,45 +22,64 @@ async def update_wallet_balance(wallet_id: str, amount: int):
) )
# manually send this for now # manually send this for now
await internal_invoice_queue.put(internal_id) await internal_invoice_queue.put(internal_id)
return payment return payment
async def get_admin_settings() -> AdminSettings: async def get_admin_settings() -> Optional[AdminSettings]:
row = await db.fetchone("SELECT * FROM admin.settings") row = await db.fetchone("SELECT * FROM admin.settings")
admin_settings = AdminSettings( if not row:
**row, lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources return None
return AdminSettings(
lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources, **row
) )
for key, _ in row.items():
if hasattr(admin_settings, key):
setattr(admin_settings, key, getattr(settings, key))
return admin_settings
async def update_admin_settings(data: UpdateSettings) -> Optional[AdminSettings]:
fields = []
# TODO: issue typens?
# somehow data, is type dict, but should be type UpdateSettings
# for key, value in data.dict().items(): #type: ignore
for key, value in data.items(): # type: ignore
if not key in readonly_variables:
setattr(settings, key, value)
if type(value) == list:
joined = ",".join(value)
fields.append(f"{key} = '{joined}'")
if type(value) == int or type(value) == float:
fields.append(f"{key} = {value}")
if type(value) == bool:
fields.append(f"{key} = {'true' if value else 'false'}")
if type(value) == str:
value = value.replace("'", "")
fields.append(f"{key} = '{value}'")
q = ", ".join(fields)
await db.execute(f"UPDATE admin.settings SET {q}")
row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved"
return AdminSettings(**row) if row else None
async def delete_admin_settings(): async def delete_admin_settings():
await db.execute("DELETE FROM admin.settings") await db.execute("DELETE FROM admin.settings")
async def update_admin_settings(data: UpdateSettings):
# TODO why are those field here, they are not in UpdateSettings
# TODO: why is UpdateSettings of type dict here? thats why type:ignore is needed
data.pop("lnbits_allowed_funding_sources") # type: ignore
data.pop("super_user") # type: ignore
q, values = get_q_and_values(data)
await db.execute(f"UPDATE admin.settings SET {q}", (values,)) # type: ignore
def get_q_and_values(data):
keys = []
values = []
for key, value in data.items():
setattr(settings, key, value)
keys.append(f"{key} = ?")
if type(value) == list:
value = ",".join(value)
values.append(value)
return ", ".join(keys), values
async def create_admin_settings():
account = await create_account()
settings.super_user = account.id
keys = []
values = ""
for key, value in settings.dict(exclude_none=True).items():
if not key in readonly_variables:
keys.append(key)
if type(value) == list:
joined = ",".join(value)
values += f"'{joined}'"
if type(value) == int or type(value) == float:
values += str(value)
if type(value) == bool:
values += "true" if value else "false"
if type(value) == str:
value = value.replace("'", "")
values += f"'{value}'"
values += ","
q = ", ".join(keys)
v = values.rstrip(",")
sql = f"INSERT INTO admin.settings ({q}) VALUES ({v})"
await db.execute(sql)

View File

@@ -15,8 +15,6 @@ async def m001_create_admin_settings_table(db):
lnbits_ad_space TEXT, lnbits_ad_space TEXT,
lnbits_ad_space_title TEXT, lnbits_ad_space_title TEXT,
lnbits_ad_space_enabled BOOLEAN, lnbits_ad_space_enabled BOOLEAN,
lnbits_data_folder TEXT,
lnbits_database_url TEXT,
lnbits_force_https TEXT, lnbits_force_https TEXT,
lnbits_reserve_fee_min TEXT, lnbits_reserve_fee_min TEXT,
lnbits_reserve_fee_percent TEXT, lnbits_reserve_fee_percent TEXT,
@@ -31,9 +29,13 @@ async def m001_create_admin_settings_table(db):
corelightning_rpc TEXT, corelightning_rpc TEXT,
eclair_url TEXT, eclair_url TEXT,
eclair_pass TEXT, eclair_pass TEXT,
lnd_cert TEXT,
lnd_admin_macaroon TEXT,
lnd_invoice_macaroon TEXT,
lnd_rest_endpoint TEXT, lnd_rest_endpoint TEXT,
lnd_rest_cert TEXT, lnd_rest_cert TEXT,
lnd_rest_macaroon TEXT, lnd_rest_macaroon TEXT,
lnd_rest_macaroon_encrypted TEXT,
lnd_grpc_endpoint TEXT, lnd_grpc_endpoint TEXT,
lnd_grpc_cert TEXT, lnd_grpc_cert TEXT,
lnd_grpc_port INTEGER, lnd_grpc_port INTEGER,

View File

@@ -1,10 +1,10 @@
from typing import List, Optional from typing import List, Optional
from fastapi import Query from fastapi import Query
from pydantic import BaseModel, validator from pydantic import BaseModel, Extra, validator
class UpdateSettings(BaseModel): class UpdateSettings(BaseModel, extra=Extra.forbid):
@validator( @validator(
"lnbits_admin_users", "lnbits_admin_users",
"lnbits_allowed_users", "lnbits_allowed_users",
@@ -73,6 +73,11 @@ class UpdateSettings(BaseModel):
lntips_admin_key: str = Query(None) lntips_admin_key: str = Query(None)
lntips_invoice_key: str = Query(None) lntips_invoice_key: str = Query(None)
boltz_mempool_space_url: str = Query(None)
boltz_mempool_space_url_ws: str = Query(None)
boltz_network: str = Query(None)
boltz_url: str = Query(None)
class AdminSettings(UpdateSettings): class AdminSettings(UpdateSettings):
lnbits_allowed_funding_sources: Optional[List[str]] lnbits_allowed_funding_sources: Optional[List[str]]

View File

@@ -1,6 +1,7 @@
from http import HTTPStatus from http import HTTPStatus
from typing import Optional
from fastapi import Body from fastapi import Body, Query
from fastapi.params import Depends from fastapi.params import Depends
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
@@ -27,7 +28,7 @@ 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() -> AdminSettings: async def api_get_settings() -> Optional[AdminSettings]:
return await get_admin_settings() return await get_admin_settings()
@@ -52,12 +53,9 @@ async def api_update_balance(
@admin_ext.put( @admin_ext.put(
"/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_update_settings( async def api_update_settings(data: UpdateSettings):
data: UpdateSettings = Body(...), await update_admin_settings(data)
): return {"status": "Success"}
settings = await update_admin_settings(data)
if settings:
return {"status": "Success", "settings": settings.dict()}
@admin_ext.delete( @admin_ext.delete(

View File

@@ -25,6 +25,8 @@ readonly_variables = [
"host", "host",
"port", "port",
"debug", "debug",
"lnbits_data_folder",
"lnbits_database_url",
"lnbits_allowed_funding_sources", "lnbits_allowed_funding_sources",
"lnbits_admin_extensions", "lnbits_admin_extensions",
"lnbits_saas_secret", "lnbits_saas_secret",
@@ -70,7 +72,7 @@ class Settings(BaseSettings):
default=["classic", "flamingo", "mint", "salvador", "monochrome", "autumn"] default=["classic", "flamingo", "mint", "salvador", "monochrome", "autumn"]
) )
lnbits_custom_logo: str = Field(default=None) lnbits_custom_logo: str = Field(default=None)
lnbits_ad_space_title: str = Field(default="Suported by") lnbits_ad_space_title: str = Field(default="Supported by")
lnbits_ad_space: str = Field( lnbits_ad_space: str = Field(
default="https://shop.lnbits.com/;/static/images/lnbits-shop-light.png;/static/images/lnbits-shop-dark.png" default="https://shop.lnbits.com/;/static/images/lnbits-shop-light.png;/static/images/lnbits-shop-dark.png"
) # sneaky sneaky ) # sneaky sneaky
@@ -199,25 +201,30 @@ def set_cli_settings(**kwargs):
async def check_admin_settings(): async def check_admin_settings():
if settings.lnbits_admin_ui: if settings.lnbits_admin_ui:
ext_db = importlib.import_module(f"lnbits.extensions.admin").db
async with ext_db.connect() as db:
row = await db.fetchone("SELECT * FROM admin.settings")
# create new settings if table is empty # if not imported here, circular import error
if not row or len(row) == 0: from lnbits.extensions.admin.crud import (
logger.warning( create_admin_settings,
"admin.settings empty. inserting new settings and creating admin account" get_admin_settings,
) )
row = await create_admin_settings(db)
# setting settings from database into memory # ext_db = importlib.import_module(f"lnbits.extensions.admin").db
from lnbits.extensions.admin.models import AdminSettings # async with ext_db.connect() as db:
# row = await db.fetchone("SELECT * FROM admin.settings")
sets = AdminSettings( sets = await get_admin_settings()
**row, # create new settings if table is empty
lnbits_allowed_funding_sources=settings.lnbits_allowed_funding_sources, if not sets:
logger.warning(
"admin.settings empty. inserting new settings and creating admin account"
) )
await create_admin_settings()
logger.warning("initialized admin.settings from enviroment variables.")
sets = await get_admin_settings()
if sets:
for key, value in sets.dict().items(): for key, value in sets.dict().items():
if not key in readonly_variables: if not key in readonly_variables:
try: try:
@@ -225,22 +232,24 @@ async def check_admin_settings():
except: except:
logger.error(f"error overriding setting: {key}, value: {value}") logger.error(f"error overriding setting: {key}, value: {value}")
# printing settings for debugging # printing settings for debugging
logger.debug(f"Admin settings:") logger.debug(f"Admin settings:")
for key, value in settings.dict(exclude_none=True).items(): for key, value in settings.dict(exclude_none=True).items():
logger.debug(f"{key}: {value}") logger.debug(f"{key}: {value}")
http = "https" if settings.lnbits_force_https else "http" http = "https" if settings.lnbits_force_https else "http"
admin_url = f"{http}://{settings.host}:{settings.port}/wallet?usr={settings.super_user}" admin_url = (
logger.success(f"✔️ Access admin user account at: {admin_url}") f"{http}://{settings.host}:{settings.port}/wallet?usr={settings.super_user}"
)
logger.success(f"✔️ Access admin user account at: {admin_url}")
# callback for saas # callback for saas
if ( if (
settings.lnbits_saas_callback settings.lnbits_saas_callback
and settings.lnbits_saas_secret and settings.lnbits_saas_secret
and settings.lnbits_saas_instance_id and settings.lnbits_saas_instance_id
): ):
send_admin_user_to_saas() send_admin_user_to_saas()
wallets_module = importlib.import_module("lnbits.wallets") wallets_module = importlib.import_module("lnbits.wallets")
@@ -252,39 +261,6 @@ def get_wallet_class():
return 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
account = await create_account()
settings.super_user = account.id
keys = []
values = ""
for key, value in settings.dict(exclude_none=True).items():
if not key in readonly_variables:
keys.append(key)
if type(value) == list:
joined = ",".join(value)
values += f"'{joined}'"
if type(value) == int or type(value) == float:
values += str(value)
if type(value) == bool:
values += "true" if value else "false"
if type(value) == str:
value = value.replace("'", "")
values += f"'{value}'"
values += ","
q = ", ".join(keys)
v = values.rstrip(",")
sql = f"INSERT INTO admin.settings ({q}) VALUES ({v})"
await db.execute(sql)
logger.warning("initialized admin.settings from enviroment variables.")
row = await db.fetchone("SELECT * FROM admin.settings")
assert row, "Newly updated settings couldn't be retrieved"
return row
def send_admin_user_to_saas(): def send_admin_user_to_saas():
if settings.lnbits_saas_callback: if settings.lnbits_saas_callback:
with httpx.Client() as client: with httpx.Client() as client: