diff --git a/lnbits/app.py b/lnbits/app.py index 7ff9e4eb5..1ffedb54c 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -19,6 +19,7 @@ import lnbits.settings from lnbits.core.tasks import register_task_listeners from .commands import get_admin_settings +from .config import WALLET, conf from .core import core_app from .core.views.generic import core_html_routes from .helpers import ( @@ -29,7 +30,8 @@ from .helpers import ( url_for_vendored, ) from .requestvars import g -from .settings import WALLET + +# from .settings import WALLET from .tasks import ( catch_everything_and_restart, check_pending_payments, @@ -43,7 +45,6 @@ def create_app(config_object="lnbits.settings") -> FastAPI: """Create application factory. :param config_object: The configuration object to use. """ -<<<<<<< HEAD configure_logger() app = FastAPI( @@ -55,20 +56,18 @@ def create_app(config_object="lnbits.settings") -> FastAPI: }, ) app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") -======= - app = FastAPI() - - if lnbits.settings.LNBITS_ADMIN_UI: - check_settings(app) - - app.mount("/static", StaticFiles(directory="lnbits/static"), name="static") ->>>>>>> e3a1b3ae (get admin settings at startup) app.mount( "/core/static", StaticFiles(packages=[("lnbits.core", "static")]), name="core_static", ) + if lnbits.settings.LNBITS_ADMIN_UI: + g().admin_conf = conf + check_settings(app) + + g().WALLET = WALLET + origins = ["*"] app.add_middleware( @@ -109,18 +108,27 @@ def create_app(config_object="lnbits.settings") -> FastAPI: return app - def check_settings(app: FastAPI): @app.on_event("startup") async def check_settings_admin(): + + def removeEmptyString(arr): + return list(filter(None, arr)) + while True: admin_set = await get_admin_settings() if admin_set : break print("ERROR:", admin_set) await asyncio.sleep(5) - # admin_set = await get_admin_settings() - g().admin_conf = admin_set + + admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(',')) + admin_set.allowed_users = removeEmptyString(admin_set.allowed_users.split(',')) + admin_set.admin_ext = removeEmptyString(admin_set.admin_ext.split(',')) + admin_set.disabled_ext = removeEmptyString(admin_set.disabled_ext.split(',')) + admin_set.theme = removeEmptyString(admin_set.theme.split(',')) + admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(',')) + g().admin_conf = conf.copy(update=admin_set.dict()) def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") diff --git a/lnbits/config.py b/lnbits/config.py new file mode 100644 index 000000000..02e8cf537 --- /dev/null +++ b/lnbits/config.py @@ -0,0 +1,62 @@ +import importlib +import json +from os import getenv, path +from typing import List, Optional + +from pydantic import BaseSettings, Field, validator + +wallets_module = importlib.import_module("lnbits.wallets") +wallet_class = getattr( + wallets_module, getenv("LNBITS_BACKEND_WALLET_CLASS", "VoidWallet") +) + +WALLET = wallet_class() + +def list_parse_fallback(v): + try: + return json.loads(v) + except Exception as e: + return v.replace(' ','').split(',') + +class Settings(BaseSettings): + # users + admin_users: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_USERS") + allowed_users: List[str] = Field(default_factory=list, env="LNBITS_ALLOWED_USERS") + admin_ext: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_EXTENSIONS") + disabled_ext: List[str] = Field(default_factory=list, env="LNBITS_DISABLED_EXTENSIONS") + funding_source: str = Field(default="VoidWallet", env="LNBITS_BACKEND_WALLET_CLASS") + # ops + data_folder: str = Field(default=None, env="LNBITS_DATA_FOLDER") + database_url: str = Field(default=None, env="LNBITS_DATABASE_URL") + force_https: bool = Field(default=True, env="LNBITS_FORCE_HTTPS") + service_fee: float = Field(default=0, env="LNBITS_SERVICE_FEE") + hide_api: bool = Field(default=False, env="LNBITS_HIDE_API") + denomination: str = Field(default="sats", env="LNBITS_DENOMINATION") + # Change theme + site_title: str = Field(default=None, env="LNBITS_SITE_TITLE") + site_tagline: str = Field(default=None, env="LNBITS_SITE_TAGLINE") + site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") + default_wallet_name: str = Field(default=None, env="LNBITS_DEFAULT_WALLET_NAME") + theme: List[str] = Field(default="classic, flamingo, mint, salvador, monochrome, autumn", env="LNBITS_THEME_OPTIONS") + ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") + # .env + env: Optional[str] + debug: Optional[str] + host: Optional[str] + port: Optional[str] + lnbits_path: Optional[str] = path.dirname(path.realpath(__file__)) + + # @validator('admin_users', 'allowed_users', 'admin_ext', 'disabled_ext', pre=True) + # def validate(cls, val): + # print(val) + # return val.split(',') + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + case_sensitive = False + json_loads = list_parse_fallback + + +conf = Settings() +WALLET = wallet_class() diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 872d6c97b..6fccb8ee6 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -40,7 +40,7 @@ async def update_admin(user: str, **kwargs) -> Admin: # new_settings = await get_admin() # return new_settings -async def get_admin() -> List[Admin]: +async def get_admin() -> Admin: row = await db.fetchone("SELECT * FROM admin") return Admin(**row) if row else None diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 13b769232..574f772d1 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -2,93 +2,151 @@ from os import getenv from sqlalchemy.exc import OperationalError # type: ignore +from lnbits.config import conf from lnbits.helpers import urlsafe_short_hash async def m001_create_admin_table(db): - user = None - site_title = None - site_tagline = None - site_description = None - allowed_users = None - admin_users = None - default_wallet_name = None - data_folder = None - disabled_ext = None - force_https = True - service_fee = 0 - funding_source = "" + # users/server + user = conf.admin_users[0] + admin_users = ",".join(conf.admin_users) + allowed_users = ",".join(conf.allowed_users) + admin_ext = ",".join(conf.admin_ext) + disabled_ext = ",".join(conf.disabled_ext) + funding_source = conf.funding_source + #operational + data_folder = conf.data_folder + database_url = conf.database_url + force_https = conf.force_https + service_fee = conf.service_fee + hide_api = conf.hide_api + denomination = conf.denomination + # Theme'ing + site_title = conf.site_title + site_tagline = conf.site_tagline + site_description = conf.site_description + default_wallet_name = conf.default_wallet_name + theme = ",".join(conf.theme) + ad_space = ",".join(conf.ad_space) - if getenv("LNBITS_SITE_TITLE"): - site_title = getenv("LNBITS_SITE_TITLE") + # if getenv("LNBITS_ADMIN_EXTENSIONS"): + # admin_ext = getenv("LNBITS_ADMIN_EXTENSIONS") - if getenv("LNBITS_SITE_TAGLINE"): - site_tagline = getenv("LNBITS_SITE_TAGLINE") + # if getenv("LNBITS_DATABASE_URL"): + # database_url = getenv("LNBITS_DATABASE_URL") - if getenv("LNBITS_SITE_DESCRIPTION"): - site_description = getenv("LNBITS_SITE_DESCRIPTION") + # if getenv("LNBITS_HIDE_API"): + # hide_api = getenv("LNBITS_HIDE_API") - if getenv("LNBITS_ALLOWED_USERS"): - allowed_users = getenv("LNBITS_ALLOWED_USERS") + # if getenv("LNBITS_THEME_OPTIONS"): + # theme = getenv("LNBITS_THEME_OPTIONS") - if getenv("LNBITS_ADMIN_USERS"): - admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) - user = admin_users.split(',')[0] + # if getenv("LNBITS_AD_SPACE"): + # ad_space = getenv("LNBITS_AD_SPACE") - if getenv("LNBITS_DEFAULT_WALLET_NAME"): - default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") + # if getenv("LNBITS_SITE_TITLE"): + # site_title = getenv("LNBITS_SITE_TITLE") - if getenv("LNBITS_DATA_FOLDER"): - data_folder = getenv("LNBITS_DATA_FOLDER") + # if getenv("LNBITS_SITE_TAGLINE"): + # site_tagline = getenv("LNBITS_SITE_TAGLINE") - if getenv("LNBITS_DISABLED_EXTENSIONS"): - disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") + # if getenv("LNBITS_SITE_DESCRIPTION"): + # site_description = getenv("LNBITS_SITE_DESCRIPTION") - if getenv("LNBITS_FORCE_HTTPS"): - force_https = getenv("LNBITS_FORCE_HTTPS") + # if getenv("LNBITS_ALLOWED_USERS"): + # allowed_users = getenv("LNBITS_ALLOWED_USERS") - if getenv("LNBITS_SERVICE_FEE"): - service_fee = getenv("LNBITS_SERVICE_FEE") + # if getenv("LNBITS_ADMIN_USERS"): + # admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) + # user = admin_users.split(',')[0] + + # if getenv("LNBITS_DEFAULT_WALLET_NAME"): + # default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") - if getenv("LNBITS_BACKEND_WALLET_CLASS"): - funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") + # if getenv("LNBITS_DATA_FOLDER"): + # data_folder = getenv("LNBITS_DATA_FOLDER") + + # if getenv("LNBITS_DISABLED_EXTENSIONS"): + # disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") + + # if getenv("LNBITS_FORCE_HTTPS"): + # force_https = getenv("LNBITS_FORCE_HTTPS") + + # if getenv("LNBITS_SERVICE_FEE"): + # service_fee = getenv("LNBITS_SERVICE_FEE") + + # if getenv("LNBITS_DENOMINATION"): + # denomination = getenv("LNBITS_DENOMINATION", "sats") + + # if getenv("LNBITS_BACKEND_WALLET_CLASS"): + # funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") await db.execute( """ CREATE TABLE IF NOT EXISTS admin ( - "user" TEXT, + "user" TEXT PRIMARY KEY, + admin_users TEXT, + allowed_users TEXT, + admin_ext TEXT, + disabled_ext TEXT, + funding_source TEXT, + data_folder TEXT, + database_url TEXT, + force_https BOOLEAN, + service_fee REAL, + hide_api BOOLEAN, + denomination TEXT, site_title TEXT, site_tagline TEXT, site_description TEXT, - admin_users TEXT, - allowed_users TEXT, default_wallet_name TEXT, - data_folder TEXT, - disabled_ext TEXT, - force_https BOOLEAN, - service_fee REAL, - funding_source TEXT + theme TEXT, + ad_space TEXT ); """ ) await db.execute( """ - INSERT INTO admin ("user", site_title, site_tagline, site_description, admin_users, allowed_users, default_wallet_name, data_folder, disabled_ext, force_https, service_fee, funding_source) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - user.strip(), + INSERT INTO admin ( + "user", + admin_users, + allowed_users, + admin_ext, + disabled_ext, + funding_source, + data_folder, + database_url, + force_https, + service_fee, + hide_api, + denomination, site_title, site_tagline, site_description, - admin_users[1:], - allowed_users, default_wallet_name, - data_folder, + theme, + ad_space) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + user, + admin_users, + allowed_users, + admin_ext, disabled_ext, + funding_source, + data_folder, + database_url, force_https, service_fee, - funding_source, + hide_api, + denomination, + site_title, + site_tagline, + site_description, + default_wallet_name, + theme, + ad_space, ), ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 4080ff018..f7c64de55 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -2,7 +2,7 @@ from sqlite3 import Row from typing import List, Optional from fastapi import Query -from pydantic import BaseModel +from pydantic import BaseModel, Field class UpdateAdminSettings(BaseModel): @@ -19,18 +19,27 @@ class UpdateAdminSettings(BaseModel): funding_source: Optional[str] class Admin(BaseModel): + # users user: str + admin_users: Optional[str] + allowed_users: Optional[str] + admin_ext: Optional[str] + disabled_ext: Optional[str] + funding_source: Optional[str] + # ops + data_folder: Optional[str] + database_url: Optional[str] + force_https: bool = Field(default=True) + service_fee: float = Field(default=0) + hide_api: bool = Field(default=False) + # Change theme site_title: Optional[str] site_tagline: Optional[str] site_description: Optional[str] - allowed_users: Optional[str] - admin_users: str - default_wallet_name: str - data_folder: str - disabled_ext: str - force_https: Optional[bool] = Query(True) - service_fee: float - funding_source: str + default_wallet_name: Optional[str] + denomination: str = Field(default="sats") + theme: Optional[str] + ad_space: Optional[str] @classmethod def from_row(cls, row: Row) -> "Admin": diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py index 00a0c99fc..105f05a10 100644 --- a/lnbits/extensions/admin/views.py +++ b/lnbits/extensions/admin/views.py @@ -19,15 +19,17 @@ templates = Jinja2Templates(directory="templates") @admin_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): admin = await get_admin() - print(g()) funding = [f.dict() for f in await get_funding()] - + error, balance = await g().WALLET.status() print("ADMIN", admin.dict()) + print(g().admin_conf) return admin_renderer().TemplateResponse( "admin/index.html", { "request": request, "user": user.dict(), "admin": admin.dict(), - "funding": funding + "funding": funding, + "settings": g().admin_conf.dict(), + "balance": balance } ) diff --git a/lnbits/settings.py b/lnbits/settings.py index 43cb87cbe..ed5c77f7e 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -4,7 +4,7 @@ from email.policy import default from os import path from typing import List -from environs import Env # type: ignore +from environs import Env env = Env() env.read_env()