[feat] install extensions from dir (#2781)

* feat: search ext dir and install
* fix: `upgrade_hash` logic
* chore: clean-up `upgrade_hash` logic
* fix: screen refresh
* fix: ignore non-ext dirs
* fix: ext migration
This commit is contained in:
Vlad Stan 2024-11-28 12:51:29 +02:00 committed by GitHub
parent f5ccf5c157
commit 0547abe54a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 64 additions and 13 deletions

View file

@ -21,6 +21,7 @@ from lnbits.core.crud import (
get_installed_extensions,
update_installed_extension_state,
)
from lnbits.core.crud.extensions import create_installed_extension
from lnbits.core.helpers import migrate_extension_database
from lnbits.core.services.extensions import deactivate_extension, get_valid_extensions
from lnbits.core.tasks import ( # watchdog_task
@ -265,6 +266,25 @@ async def build_all_installed_extensions_list(
installed_extensions = await get_installed_extensions()
settings.lnbits_all_extensions_ids = {e.id for e in installed_extensions}
for ext_dir in Path(settings.lnbits_extensions_path, "extensions").iterdir():
try:
if not ext_dir.is_dir():
continue
ext_id = ext_dir.name
if ext_id in settings.lnbits_all_extensions_ids:
continue
ext_info = InstallableExtension.from_ext_dir(ext_id)
if not ext_info:
continue
installed_extensions.append(ext_info)
await create_installed_extension(ext_info)
current_version = await get_db_version(ext_id)
await migrate_extension_database(ext_info, current_version)
except Exception as e:
logger.warning(e)
for ext_id in settings.lnbits_extensions_default_install:
if ext_id in settings.lnbits_all_extensions_ids:
continue

View file

@ -169,11 +169,7 @@ class Extension(BaseModel):
name=ext_info.name,
short_description=ext_info.short_description,
tile=ext_info.icon,
upgrade_hash=(
ext_info.hash
if settings.extension_has_been_activated(ext_info.id)
else ""
),
upgrade_hash=ext_info.hash if ext_info.ext_upgrade_dir.is_dir() else "",
)
@ -551,6 +547,41 @@ class InstallableExtension(BaseModel):
meta=meta,
)
@classmethod
def from_ext_dir(cls, ext_id: str) -> Optional[InstallableExtension]:
try:
conf_path = Path(
settings.lnbits_extensions_path, "extensions", ext_id, "config.json"
)
if not conf_path.is_file():
return None
with open(conf_path, "r+") as json_file:
config_json = json.load(json_file)
version = config_json.get("version", "0.0")
return InstallableExtension(
id=ext_id,
name=config_json.get("name", ext_id),
active=True,
version=version,
short_description=config_json.get("short_description"),
icon=config_json.get("tile"),
meta=ExtensionMeta(
installed_release=ExtensionRelease(
name=ext_id,
version=version,
archive=f"{conf_path}",
source_repo=f"{conf_path}",
min_lnbits_version=config_json.get("min_lnbits_version"),
)
),
)
except Exception as e:
logger.warning(e)
return None
@classmethod
async def get_installable_extensions(
cls,

View file

@ -1023,6 +1023,10 @@
})
if (this.uninstallAndDropDb) {
this.showDropDb()
} else {
setTimeout(() => {
window.location.reload()
}, 300)
}
})
.catch(err => {
@ -1051,6 +1055,9 @@
type: 'positive',
message: 'Extension DB deleted!'
})
setTimeout(() => {
window.location.reload()
}, 300)
})
.catch(err => {
LNbits.utils.notifyApiError(err)
@ -1073,6 +1080,7 @@
})
.catch(err => {
LNbits.utils.notifyApiError(err)
extension.isActive = false
extension.inProgress = false
})
},

View file

@ -129,10 +129,6 @@ class InstalledExtensionsSettings(LNbitsSettings):
# list of all extension ids
lnbits_all_extensions_ids: set[str] = Field(default=[])
# list of all extension ids that have been activated at least once
# only add to this set, do not remove
lnbits_activated_paths_extensions_ids: set[str] = Field(default=[])
def find_extension_redirect(
self, path: str, req_headers: list[tuple[bytes, bytes]]
) -> Optional[RedirectPath]:
@ -165,15 +161,11 @@ class InstalledExtensionsSettings(LNbitsSettings):
self._activate_extension_redirects(ext_id, ext_redirects)
self.lnbits_all_extensions_ids.add(ext_id)
self.lnbits_activated_paths_extensions_ids.add(ext_id)
def deactivate_extension_paths(self, ext_id: str):
self.lnbits_deactivated_extensions.add(ext_id)
self._remove_extension_redirects(ext_id)
def extension_has_been_activated(self, ext_id: str) -> bool:
return ext_id in settings.lnbits_activated_paths_extensions_ids
def extension_upgrade_hash(self, ext_id: str) -> str:
return settings.lnbits_upgraded_extensions.get(ext_id, "")