From ff12a76b42c1e070d422d56a28b5cd620d825aba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 7 Oct 2024 11:45:27 +0200 Subject: [PATCH] fix dynamic fields and ext db migration --- lnbits/app.py | 2 +- lnbits/core/extensions/extension_manager.py | 2 +- lnbits/core/helpers.py | 25 ++++++++++++--------- lnbits/db.py | 8 ++++--- lnbits/static/js/components.js | 6 ++--- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index 0ee7f4f5b..ecb0164c3 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -314,7 +314,7 @@ async def restore_installed_extension(app: FastAPI, ext: InstallableExtension): register_ext_routes(app, extension) current_version = (await get_dbversions()).get(ext.id, 0) - await migrate_extension_database(extension, current_version) + await migrate_extension_database(ext, current_version) # mount routes for the new version core_app_extra.register_new_ext_routes(extension) diff --git a/lnbits/core/extensions/extension_manager.py b/lnbits/core/extensions/extension_manager.py index a716b66be..c15469354 100644 --- a/lnbits/core/extensions/extension_manager.py +++ b/lnbits/core/extensions/extension_manager.py @@ -29,7 +29,7 @@ async def install_extension(ext_info: InstallableExtension) -> Extension: ext_info.extract_archive() db_version = (await get_dbversions()).get(ext_id, 0) - await migrate_extension_database(extension, db_version) + await migrate_extension_database(ext_info, db_version) await create_installed_extension(ext_info) diff --git a/lnbits/core/helpers.py b/lnbits/core/helpers.py index 5d2dd286f..35087b2d8 100644 --- a/lnbits/core/helpers.py +++ b/lnbits/core/helpers.py @@ -13,23 +13,22 @@ from lnbits.core.crud import ( update_migration_version, ) from lnbits.core.db import db as core_db -from lnbits.core.extensions.models import ( - Extension, -) +from lnbits.core.extensions.models import InstallableExtension from lnbits.db import COCKROACH, POSTGRES, SQLITE, Connection from lnbits.settings import settings -async def migrate_extension_database(ext: Extension, current_version): +async def migrate_extension_database(ext: InstallableExtension, current_version: int): + try: ext_migrations = importlib.import_module(f"{ext.module_name}.migrations") ext_db = importlib.import_module(ext.module_name).db except ImportError as exc: logger.error(exc) - raise ImportError(f"Cannot import module for extension '{ext.code}'.") from exc + raise ImportError(f"Cannot import module for extension '{ext.id}'.") from exc async with ext_db.connect() as ext_conn: - await run_migration(ext_conn, ext_migrations, ext.code, current_version) + await run_migration(ext_conn, ext_migrations, ext.id, current_version) async def run_migration( @@ -72,6 +71,7 @@ async def load_disabled_extension_list() -> None: async def migrate_databases(): """Creates the necessary databases if they don't exist already; or migrates them.""" + current_versions = await get_dbversions() async with core_db.connect() as conn: exists = False if conn.type == SQLITE: @@ -87,7 +87,6 @@ async def migrate_databases(): if not exists: await core_migrations.m000_create_migrations_table(conn) - current_versions = await get_dbversions(conn) core_version = current_versions.get("core", 0) await run_migration(conn, core_migrations, "core", core_version) @@ -95,13 +94,17 @@ async def migrate_databases(): # `installed_extensions` table has been created await load_disabled_extension_list() - # todo: revisit, use installed extensions - for ext in Extension.get_valid_extensions(False): - current_version = current_versions.get(ext.code, 0) + for ext in await get_installed_extensions(): + current_version = current_versions.get(ext.id) + if current_version is None: + logger.warning( + f"Extension {ext.id} has no migration version. This should not happen." + ) + continue try: await migrate_extension_database(ext, current_version) except Exception as e: - logger.exception(f"Error migrating extension {ext.code}: {e}") + logger.exception(f"Error migrating extension {ext.id}: {e}") logger.info("✔️ All migrations done.") diff --git a/lnbits/db.py b/lnbits/db.py index 3f1b931a7..7e3fda08b 100644 --- a/lnbits/db.py +++ b/lnbits/db.py @@ -579,12 +579,14 @@ def insert_query(table_name: str, model: BaseModel) -> str: return f"INSERT INTO {table_name} ({fields}) VALUES ({values})" -def update_query(table_name: str, model: BaseModel, where: str = "id = :id") -> str: +def update_query( + table_name: str, model: BaseModel, where: str = "WHERE id = :id" +) -> str: """ Generate an update query with placeholders for a given table and model :param table_name: Name of the table :param model: Pydantic model - :param where: Where string, default to `id = :id` + :param where: Where string, default to `WHERE id = :id` """ fields = [] for field in model_to_dict(model).keys(): @@ -592,7 +594,7 @@ def update_query(table_name: str, model: BaseModel, where: str = "id = :id") -> # add quotes to keys to avoid SQL conflicts (e.g. `user` is a reserved keyword) fields.append(f'"{field}" = {placeholder}') query = ", ".join(fields) - return f"UPDATE {table_name} SET {query} WHERE {where}" + return f"UPDATE {table_name} SET {query} {where}" def model_to_dict(model: BaseModel) -> dict: diff --git a/lnbits/static/js/components.js b/lnbits/static/js/components.js index bccdb9481..85c69d17d 100644 --- a/lnbits/static/js/components.js +++ b/lnbits/static/js/components.js @@ -405,7 +405,7 @@ window.app.component('lnbits-notifications-btn', { window.app.component('lnbits-dynamic-fields', { template: '#lnbits-dynamic-fields', mixins: [window.windowMixin], - props: ['options', 'value'], + props: ['options', 'modelValue'], data() { return { formData: null, @@ -427,11 +427,11 @@ window.app.component('lnbits-dynamic-fields', { }, {}) }, handleValueChanged() { - this.$emit('input', this.formData) + this.$emit('update:model-value', this.formData) } }, created() { - this.formData = this.buildData(this.options, this.value) + this.formData = this.buildData(this.options, this.modelValue) } })