From 1c38b129c0dc86f9e80c15d44a448c8a2f5ddc6f Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 18 Oct 2023 14:11:58 +0300 Subject: [PATCH] [BUG] Installation of new extensions via LNBITS_EXTENSIONS_DEFAULT_INSTALL does not select the right version (#2046) * fix: guard against bad versions (eg: `v0.2-ui-api-updates`) * fix: use the latest release on auto-install --- lnbits/app.py | 13 +++++++++++-- lnbits/extension_manager.py | 17 ++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index a5ef2ee8f..5438b2b3d 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -39,7 +39,12 @@ from .core.db import core_app_extra from .core.services import check_admin_settings, check_webpush_settings from .core.views.api import add_installed_extension from .core.views.generic import update_installed_extension_state -from .extension_manager import Extension, InstallableExtension, get_valid_extensions +from .extension_manager import ( + Extension, + InstallableExtension, + get_valid_extensions, + version_parse, +) from .helpers import template_renderer from .middleware import ( CustomGZipMiddleware, @@ -217,7 +222,11 @@ async def build_all_installed_extensions_list() -> List[InstallableExtension]: continue ext_releases = await InstallableExtension.get_extension_releases(ext_id) - release = ext_releases[0] if len(ext_releases) else None + ext_releases = sorted( + ext_releases, key=lambda r: version_parse(r.version), reverse=True + ) + + release = next((e for e in ext_releases if e.is_version_compatible), None) if release: ext_info = InstallableExtension( diff --git a/lnbits/extension_manager.py b/lnbits/extension_manager.py index 94ec52fb2..ed5f38a09 100644 --- a/lnbits/extension_manager.py +++ b/lnbits/extension_manager.py @@ -37,7 +37,7 @@ class ExplicitRelease(BaseModel): def is_version_compatible(self): if not self.min_lnbits_version: return True - return version.parse(self.min_lnbits_version) <= version.parse(settings.version) + return version_parse(self.min_lnbits_version) <= version_parse(settings.version) class GitHubRelease(BaseModel): @@ -75,7 +75,7 @@ class ExtensionConfig(BaseModel): def is_version_compatible(self): if not self.min_lnbits_version: return True - return version.parse(self.min_lnbits_version) <= version.parse(settings.version) + return version_parse(self.min_lnbits_version) <= version_parse(settings.version) def download_url(url, save_path): @@ -470,7 +470,7 @@ class InstallableExtension(BaseModel): if not self.latest_release: self.latest_release = release return - if version.parse(self.latest_release.version) < version.parse(release.version): + if version_parse(self.latest_release.version) < version_parse(release.version): self.latest_release = release @classmethod @@ -613,3 +613,14 @@ def get_valid_extensions() -> List[Extension]: return [ extension for extension in ExtensionManager().extensions if extension.is_valid ] + + +def version_parse(v: str): + """ + Wrapper for version.parse() that does not throw if the version is invalid. + Instead it return the lowest possible version ("0.0.0") + """ + try: + return version.parse(v) + except Exception: + return version.parse("0.0.0")