custom_components/bahmcloud_store/views.py aktualisiert
This commit is contained in:
@@ -16,14 +16,12 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _render_markdown_server_side(md: str) -> str | None:
|
||||
"""Render Markdown -> sanitized HTML (server-side)."""
|
||||
text = (md or "").strip()
|
||||
if not text:
|
||||
return None
|
||||
|
||||
html: str | None = None
|
||||
|
||||
# 1) python-markdown
|
||||
try:
|
||||
import markdown as mdlib # type: ignore
|
||||
|
||||
@@ -39,7 +37,6 @@ def _render_markdown_server_side(md: str) -> str | None:
|
||||
if not html:
|
||||
return None
|
||||
|
||||
# 2) Sanitize via bleach
|
||||
try:
|
||||
import bleach # type: ignore
|
||||
|
||||
@@ -124,16 +121,6 @@ def _maybe_decode_base64(content: str, encoding: Any) -> str | None:
|
||||
|
||||
|
||||
def _extract_text_recursive(obj: Any, depth: int = 0) -> str | None:
|
||||
"""
|
||||
Robust extraction for README markdown.
|
||||
|
||||
Handles:
|
||||
- str / bytes
|
||||
- dict with:
|
||||
- {content: "...", encoding: "base64"} (possibly nested)
|
||||
- {readme: "..."} etc.
|
||||
- list of dicts (pick first matching)
|
||||
"""
|
||||
if obj is None:
|
||||
return None
|
||||
|
||||
@@ -150,20 +137,16 @@ def _extract_text_recursive(obj: Any, depth: int = 0) -> str | None:
|
||||
return None
|
||||
|
||||
if isinstance(obj, dict):
|
||||
# 1) If it looks like "file content"
|
||||
content = obj.get("content")
|
||||
encoding = obj.get("encoding")
|
||||
|
||||
# Base64 decode if possible
|
||||
decoded = _maybe_decode_base64(content, encoding)
|
||||
if decoded:
|
||||
return decoded
|
||||
|
||||
# content may already be plain text
|
||||
if isinstance(content, str) and (not isinstance(encoding, str) or not encoding.strip()):
|
||||
return content
|
||||
|
||||
# 2) direct text keys (readme/markdown/text/body/data)
|
||||
for k in _TEXT_KEYS:
|
||||
v = obj.get(k)
|
||||
if isinstance(v, str):
|
||||
@@ -174,7 +157,6 @@ def _extract_text_recursive(obj: Any, depth: int = 0) -> str | None:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# 3) Sometimes nested under "file" / "result" / "payload" etc.
|
||||
for v in obj.values():
|
||||
out = _extract_text_recursive(v, depth + 1)
|
||||
if out:
|
||||
@@ -197,7 +179,7 @@ class StaticAssetsView(HomeAssistantView):
|
||||
name = "api:bahmcloud_store_static"
|
||||
requires_auth = False
|
||||
|
||||
async def get(self, request: web.Request, path: str) -> web.Response:
|
||||
async def get(self, request: web.Request, path: str) -> web.StreamResponse:
|
||||
base = Path(__file__).resolve().parent / "panel"
|
||||
base_resolved = base.resolve()
|
||||
|
||||
@@ -217,24 +199,7 @@ class StaticAssetsView(HomeAssistantView):
|
||||
_LOGGER.error("BCS static asset not found: %s", target)
|
||||
return web.Response(status=404)
|
||||
|
||||
content_type = "text/plain"
|
||||
charset = None
|
||||
|
||||
if target.suffix == ".js":
|
||||
content_type = "application/javascript"
|
||||
charset = "utf-8"
|
||||
elif target.suffix == ".html":
|
||||
content_type = "text/html"
|
||||
charset = "utf-8"
|
||||
elif target.suffix == ".css":
|
||||
content_type = "text/css"
|
||||
charset = "utf-8"
|
||||
elif target.suffix == ".svg":
|
||||
content_type = "image/svg+xml"
|
||||
elif target.suffix == ".png":
|
||||
content_type = "image/png"
|
||||
|
||||
resp = web.Response(body=target.read_bytes(), content_type=content_type, charset=charset)
|
||||
resp = web.FileResponse(path=target)
|
||||
resp.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
||||
resp.headers["Pragma"] = "no-cache"
|
||||
return resp
|
||||
@@ -254,33 +219,16 @@ class BCSApiView(HomeAssistantView):
|
||||
)
|
||||
|
||||
async def post(self, request: web.Request) -> web.Response:
|
||||
"""
|
||||
Supported operations:
|
||||
|
||||
1) Full refresh:
|
||||
POST /api/bcs?action=refresh
|
||||
|
||||
2) JSON operations (body based):
|
||||
{
|
||||
"op": "add_custom_repo",
|
||||
"url": "...",
|
||||
"name": "..."
|
||||
}
|
||||
"""
|
||||
|
||||
# --- Phase B: Manual full refresh trigger ---
|
||||
action = request.query.get("action")
|
||||
if action == "refresh":
|
||||
_LOGGER.info("BCS manual refresh triggered via API")
|
||||
try:
|
||||
# Centralized service (same path as timer), includes logging and signal_updated
|
||||
await self.core.full_refresh(source="manual")
|
||||
return web.json_response({"ok": True})
|
||||
except Exception as e:
|
||||
_LOGGER.error("BCS manual refresh failed: %s", e)
|
||||
return web.json_response({"ok": False, "message": "Refresh failed"}, status=500)
|
||||
|
||||
# --- Existing JSON based operations ---
|
||||
try:
|
||||
data = await request.json()
|
||||
except Exception:
|
||||
@@ -340,6 +288,5 @@ class BCSReadmeView(HomeAssistantView):
|
||||
)
|
||||
|
||||
md_str = str(md)
|
||||
|
||||
html = _render_markdown_server_side(md_str)
|
||||
return web.json_response({"ok": True, "readme": md_str, "html": html})
|
||||
|
||||
Reference in New Issue
Block a user