feat: separate extension release into new API

This commit is contained in:
Vlad Stan 2023-01-16 14:56:34 +02:00
parent a73e8ae44d
commit 27b308ae1a
4 changed files with 74 additions and 17 deletions

View File

@ -153,18 +153,25 @@
<q-dialog v-model="showUpgradeDialog">
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
<div class="col-12 col-md-5 q-gutter-y-md">
<q-card>
<div class="col-12 col-md-5 q-gutter-y-md" v-if="selectedExtensionRepos">
<q-card v-for="repo of Object.keys(selectedExtensionRepos)" :key="repo">
<q-card-section>
<h6 class="text-subtitle1 q-my-none">Repo name</h6>
<h6 class="text-subtitle1 q-my-none">
<q-badge color="primary" rounded
><small v-text="repo"></small
></q-badge>
</h6>
</q-card-section>
<q-card-section class="q-pa-none">
<q-separator></q-separator>
<q-list>
<q-expansion-item
v-for="release of selectedExtensionRepos[repo]"
:key="release.version"
group="extras"
icon="download"
label="Version"
:label="release.description"
:caption="'Version: ' + release.version"
:content-inset-level="0.5"
>
<q-expansion-item
@ -229,6 +236,8 @@
showUpgradeDialog: false,
showDetailsDialog: false,
selectedExtension: null,
selectedExtensionReleases: null,
selectedExtensionRepos: null,
maxStars: 0
}
},
@ -317,12 +326,19 @@
console.log('### showUpgrade')
this.selectedExtension = extension
this.showUpgradeDialog = true
const releases = await LNbits.api.request(
const {data} = await LNbits.api.request(
'GET',
`/api/v1/extension/${extension.id}/releases?usr=${this.g.user.id}`,
this.g.user.wallets[0].adminkey
)
console.log('### releases', releases)
this.selectedExtensionReleases = data
this.selectedExtensionRepos = data.reduce((repos, release) => {
repos[release.source_repo] = repos[release.source_repo] || []
repos[release.source_repo].push(release)
return repos
}, {})
console.log('### releases', this.selectedExtensionReleases)
console.log('### repos', this.selectedExtensionRepos)
},
showExtensionDetails: function (extension) {

View File

@ -42,6 +42,7 @@ from lnbits.decorators import (
)
from lnbits.extension_manger import (
Extension,
ExtensionRelease,
InstallableExtension,
get_valid_extensions,
)
@ -800,12 +801,11 @@ async def api_uninstall_extension(ext_id: str, user: User = Depends(check_admin)
@core_app.get("/api/v1/extension/{ext_id}/releases")
async def get_extension_releases(ext_id: str, user: User = Depends(check_admin)):
try:
installable_extensions: List[
InstallableExtension
] = await InstallableExtension.get_installable_extensions()
extensions = [e for e in installable_extensions if e.id == ext_id]
extension_releases: List[
ExtensionRelease
] = await InstallableExtension.get_extension_releases(ext_id)
return extensions
return extension_releases
except Exception as ex:
raise HTTPException(

View File

@ -113,7 +113,9 @@ async def extensions_install(
"dependencies": ext.dependencies,
"isInstalled": ext.id in installed_extensions,
"isActive": not ext.id in inactive_extensions,
"release": dict(ext.release) if ext.release else None,
"latestRelease": dict(ext.latest_release)
if ext.latest_release
else None,
},
extension_list,
)

View File

@ -6,7 +6,6 @@ import sys
import urllib.request
import zipfile
from http import HTTPStatus
from platform import release
from typing import List, NamedTuple, Optional
import httpx
@ -107,6 +106,7 @@ class ExtensionRelease(BaseModel):
name: str
version: str
archive: str
source_repo: str
hash: Optional[str]
published_at: Optional[str]
url: Optional[str]
@ -118,6 +118,7 @@ class ExtensionRelease(BaseModel):
name=r["name"],
version=r["tag_name"],
archive=r["zipball_url"],
# source_repo=r[]
# description=r["body"], # bad for JSON
published_at=r["published_at"],
url=r["html_url"],
@ -127,7 +128,7 @@ class ExtensionRelease(BaseModel):
class InstallableExtension(BaseModel):
id: str
name: str
archive: str #todo: move to installed_release
archive: str # todo: move to installed_release
hash: str
short_description: Optional[str] = None
details: Optional[str] = None
@ -137,7 +138,9 @@ class InstallableExtension(BaseModel):
is_admin_only: bool = False
version: str = "none" # todo: move to Release
stars: int = 0
release: Optional[ExtensionRelease]
latest_release: Optional[ExtensionRelease]
installed_release: Optional[ExtensionRelease]
all_releases: List[ExtensionRelease] = []
@property
def zip_path(self) -> str:
@ -233,7 +236,7 @@ class InstallableExtension(BaseModel):
version="0",
stars=repo["stargazers_count"],
icon_url=icon_to_github_url(org, config.get("tile")),
release=ExtensionRelease.from_github_release(latest_release),
latest_release=ExtensionRelease.from_github_release(latest_release),
)
except Exception as e:
logger.warning(e)
@ -268,6 +271,7 @@ class InstallableExtension(BaseModel):
@classmethod
async def get_installable_extensions(cls) -> List["InstallableExtension"]:
extension_list: List[InstallableExtension] = []
extension_id_list: List[str] = []
async with httpx.AsyncClient() as client:
for url in settings.lnbits_extensions_manifests:
@ -278,7 +282,9 @@ class InstallableExtension(BaseModel):
continue
manifest = resp.json()
if "extensions" in manifest:
for e in manifest["extensions"] or []:
for e in manifest["extensions"]:
if e["id"] in extension_id_list:
continue
extension_list += [
InstallableExtension(
id=e["id"],
@ -293,18 +299,51 @@ class InstallableExtension(BaseModel):
else [],
)
]
extension_id_list += [e["id"]]
if "repos" in manifest:
for r in manifest["repos"]:
ext = await InstallableExtension.from_repo(
r["organisation"], r["repository"]
)
if ext:
if ext.id in extension_id_list:
continue
extension_list += [ext]
extension_id_list += [ext.id]
except Exception as e:
logger.warning(f"Manifest {url} failed with '{str(e)}'")
return extension_list
@classmethod
async def get_extension_releases(cls, ext_id: str) -> List["ExtensionRelease"]:
extension_releases: List[ExtensionRelease] = []
async with httpx.AsyncClient() as client:
for url in settings.lnbits_extensions_manifests:
try:
resp = await client.get(url)
if resp.status_code != 200:
logger.warning(f"Cannot fetch extensions manifest at: {url}")
continue
manifest = resp.json()
if "extensions" in manifest:
for e in manifest["extensions"]:
if e["id"] == ext_id:
extension_releases += [
ExtensionRelease(
name=e["name"],
version=e["version"],
archive=e["archive"],
hash=e["hash"],
source_repo=url,
description=e["shortDescription"],
)
]
except Exception as e:
logger.warning(f"Manifest {url} failed with '{str(e)}'")
return extension_releases
class InstalledExtensionMiddleware:
def __init__(self, app: ASGIApp) -> None: