From 86c86958ae1ba57a6991014aff769871184cffee Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Tue, 17 Jan 2023 16:28:24 +0200 Subject: [PATCH] refactor: more and more --- lnbits/core/crud.py | 47 +++++++++++++++++++++-------- lnbits/core/migrations.py | 4 +++ lnbits/core/views/api.py | 8 +---- lnbits/core/views/generic.py | 10 +++++-- lnbits/extension_manger.py | 58 +++++++----------------------------- 5 files changed, 56 insertions(+), 71 deletions(-) diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 64ecc1218..4919d014e 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -6,6 +6,7 @@ from uuid import uuid4 from lnbits import bolt11 from lnbits.db import COCKROACH, POSTGRES, Connection +from lnbits.extension_manger import InstallableExtension from lnbits.settings import AdminSettings, EditableSettings, SuperSettings, settings from . import db @@ -71,29 +72,39 @@ async def get_user(user_id: str, conn: Optional[Connection] = None) -> Optional[ async def add_installed_extension( - *, - ext_id: str, - version: str, - name: str, - active: bool, - meta: dict, + ext: InstallableExtension, conn: Optional[Connection] = None, ) -> None: + meta = { + "installed_release": dict(ext.installed_release) + if ext.installed_release + else None, + "dependencies": ext.dependencies, + } + + version = ext.installed_release.version if ext.installed_release else "" + await (conn or db).execute( """ - INSERT INTO installed_extensions (id, version, name, active, meta) VALUES (?, ?, ?, ?, ?) + INSERT INTO installed_extensions (id, version, name, short_description, icon, icon_url, stars, meta) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO - UPDATE SET (version, name, active, meta) = (?, ?, ?, ?) + UPDATE SET (version, name, short_description, icon, icon_url, stars, meta) = (?, ?, ?, ?, ?, ?, ?) """, ( - ext_id, + ext.id, version, - name, - active, + ext.name, + ext.short_description, + ext.icon, + ext.icon_url, + ext.stars, json.dumps(meta), version, - name, - active, + ext.name, + ext.short_description, + ext.icon, + ext.icon_url, + ext.stars, json.dumps(meta), ), ) @@ -132,6 +143,16 @@ async def get_installed_extension(ext_id: str, conn: Optional[Connection] = None return dict(row) +async def get_installed_extensions( + conn: Optional[Connection] = None, +) -> List["InstallableExtension"]: + rows = await (conn or db).fetchall( + "SELECT * FROM installed_extensions", + (), + ) + return [InstallableExtension.from_row(row) for row in rows] + + async def get_inactive_extensions(*, conn: Optional[Connection] = None) -> List[str]: inactive_extensions = await (conn or db).fetchall( """SELECT id FROM installed_extensions WHERE NOT active""", diff --git a/lnbits/core/migrations.py b/lnbits/core/migrations.py index 472a7c220..707834108 100644 --- a/lnbits/core/migrations.py +++ b/lnbits/core/migrations.py @@ -278,6 +278,10 @@ async def m009_create_installed_extensions_table(db): id TEXT PRIMARY KEY, version TEXT NOT NULL, name TEXT NOT NULL, + short_description TEXT, + icon TEXT, + icon_url TEXT, + stars INT NOT NULL DEFAULT 0, active BOOLEAN DEFAULT false, meta TEXT NOT NULL DEFAULT '{}' ); diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index f8eafad95..3e12e809e 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -747,13 +747,7 @@ async def api_install_extension( db_version = (await get_dbversions()).get(data.ext_id, 0) await migrate_extension_database(extension, db_version) - await add_installed_extension( - ext_id=data.ext_id, - version=release.version, - name=ext_info.name, - active=False, - meta={"installed_release": dict(release)}, - ) + await add_installed_extension(ext_info) settings.lnbits_disabled_extensions += [data.ext_id] # mount routes for the new version diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index f72064324..a26305e30 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -23,6 +23,7 @@ from ..crud import ( delete_wallet, get_balance_check, get_inactive_extensions, + get_installed_extensions, get_user, save_balance_notify, update_installed_extension_state, @@ -75,9 +76,12 @@ async def extensions_install( deactivate: str = Query(None), ): try: + installed_extensions: List[ + "InstallableExtension" + ] = await get_installed_extensions() extension_list: List[ InstallableExtension - ] = await InstallableExtension.get_installable_extensions() + ] = await InstallableExtension.get_installable_extensions(installed_extensions) except Exception as ex: logger.warning(ex) extension_list = [] @@ -96,7 +100,7 @@ async def extensions_install( ext_id=ext_id, active=activate != None ) - installed_extensions = list(map(lambda e: e.code, get_valid_extensions(True))) + all_extensions = list(map(lambda e: e.code, get_valid_extensions(True))) inactive_extensions = await get_inactive_extensions() extensions = list( map( @@ -108,7 +112,7 @@ async def extensions_install( "shortDescription": ext.short_description, "stars": ext.stars, "dependencies": ext.dependencies, - "isInstalled": ext.id in installed_extensions, + "isInstalled": ext.id in all_extensions, "isActive": not ext.id in inactive_extensions, "latestRelease": dict(ext.latest_release) if ext.latest_release diff --git a/lnbits/extension_manger.py b/lnbits/extension_manger.py index acba1be47..4a9fb7e4a 100644 --- a/lnbits/extension_manger.py +++ b/lnbits/extension_manger.py @@ -15,7 +15,6 @@ from loguru import logger from pydantic import BaseModel from starlette.types import ASGIApp, Receive, Scope, Send -from lnbits.core.crud import get_installed_extension from lnbits.settings import settings @@ -255,9 +254,7 @@ class InstallableExtension(BaseModel): shutil.rmtree(self.ext_upgrade_dir, True) @classmethod - async def from_row(cls, data: dict) -> Optional["InstallableExtension"]: - if not data: - return None + def from_row(cls, data: dict) -> "InstallableExtension": meta = json.loads(data["meta"]) ext = InstallableExtension(**data) if "installed_release" in meta: @@ -269,9 +266,6 @@ class InstallableExtension(BaseModel): cls, ext_id, org, repository ) -> Optional["InstallableExtension"]: try: - installed_release = await InstallableExtension.from_row( - await get_installed_extension(ext_id) - ) repo, latest_release, config = await fetch_github_repo_info(org, repository) return InstallableExtension( @@ -281,7 +275,6 @@ class InstallableExtension(BaseModel): version="0", stars=repo["stargazers_count"], icon_url=icon_to_github_url(org, config.get("tile")), - installed_release=installed_release, latest_release=ExtensionRelease.from_github_release( repo["html_url"], latest_release ), @@ -291,10 +284,7 @@ class InstallableExtension(BaseModel): return None @classmethod - async def from_manifest(cls, e: dict) -> "InstallableExtension": - installed_ext = await InstallableExtension.from_row( - await get_installed_extension(e["id"]) - ) + def from_manifest(cls, e: dict) -> "InstallableExtension": return InstallableExtension( id=e["id"], name=e["name"], @@ -302,42 +292,17 @@ class InstallableExtension(BaseModel): hash=e["hash"], short_description=e["shortDescription"], icon=e["icon"], - installed_release=installed_ext.installed_release - if installed_ext - else None, dependencies=e["dependencies"] if "dependencies" in e else [], ) - @classmethod # todo: remove - async def get_extension_info( - cls, ext_id: str, archive: str - ) -> "InstallableExtension": - installable_extensions: List[ - InstallableExtension - ] = await InstallableExtension.get_installable_extensions() - - valid_extensions = [e for e in installable_extensions if e.id == ext_id] - if len(valid_extensions) == 0: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"Unknown extension id: {ext_id}", - ) - extension = valid_extensions[0] - - # check that all dependecies are installed - installed_extensions = list(map(lambda e: e.code, get_valid_extensions(True))) - if not set(extension.dependencies).issubset(installed_extensions): - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail=f"Not all dependencies are installed: {extension.dependencies}", - ) - - return extension - @classmethod - async def get_installable_extensions(cls) -> List["InstallableExtension"]: - extension_list: List[InstallableExtension] = [] - extension_id_list: List[str] = [] + async def get_installable_extensions( + cls, installed_extensions: List["InstallableExtension"] = [] + ) -> List["InstallableExtension"]: + extension_list: List[InstallableExtension] = ( + installed_extensions if installed_extensions else [] + ) + extension_id_list: List[str] = [e.id for e in extension_list] async with httpx.AsyncClient() as client: for url in settings.lnbits_extensions_manifests: @@ -355,7 +320,6 @@ class InstallableExtension(BaseModel): r["id"], r["organisation"], r["repository"] ) if ext: - extension_list += [ext] extension_id_list += [ext.id] @@ -363,9 +327,7 @@ class InstallableExtension(BaseModel): for e in manifest["extensions"]: if e["id"] in extension_id_list: continue - extension_list += [ - await InstallableExtension.from_manifest(e) - ] + extension_list += [InstallableExtension.from_manifest(e)] extension_id_list += [e["id"]] except Exception as e: logger.warning(f"Manifest {url} failed with '{str(e)}'")