updated apps
This commit is contained in:
@@ -26,7 +26,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
from homeassistant.helpers.storage import Store
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from ..const import DOMAIN, SIGNAL_DOCUMENTS_UPDATED
|
||||
from ..const import DOMAIN, MAX_DOCS_PER_OBJECT, SIGNAL_DOCUMENTS_UPDATED
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -146,6 +146,12 @@ class DocumentStore:
|
||||
if len(content) > MAX_DOC_BYTES:
|
||||
raise ValueError("file_too_large")
|
||||
|
||||
# Per-object document cap — a runaway upload loop must not be able to
|
||||
# bloat the (single, global) documents store without bound.
|
||||
object_doc_count = sum(1 for d in self.documents.values() if d.get("object_id") == object_id)
|
||||
if object_doc_count >= MAX_DOCS_PER_OBJECT:
|
||||
raise ValueError("too_many_documents")
|
||||
|
||||
digest, wrote_new = await self.hass.async_add_executor_job(self._store_blob_sync, content)
|
||||
|
||||
# Register / adopt the blob and bump its refcount.
|
||||
@@ -172,6 +178,7 @@ class DocumentStore:
|
||||
"size": len(content),
|
||||
"tags": list(tags or []),
|
||||
"task_ids": [],
|
||||
"part_ids": [],
|
||||
"added_at": dt_util.utcnow().isoformat(),
|
||||
}
|
||||
self.documents[doc_id] = doc
|
||||
@@ -214,21 +221,41 @@ class DocumentStore:
|
||||
"title": title or url,
|
||||
"tags": list(tags or []),
|
||||
"task_ids": [],
|
||||
"part_ids": [],
|
||||
"added_at": dt_util.utcnow().isoformat(),
|
||||
}
|
||||
self.documents[doc_id] = doc
|
||||
await self._async_save()
|
||||
return {"id": doc_id, **doc}
|
||||
|
||||
async def async_import_documents(self, object_id: str, docs: list[dict[str, Any]]) -> int:
|
||||
async def async_import_documents(
|
||||
self,
|
||||
object_id: str,
|
||||
docs: list[dict[str, Any]],
|
||||
task_id_map: dict[str, str] | None = None,
|
||||
part_id_map: dict[str, str] | None = None,
|
||||
) -> int:
|
||||
"""Recreate document metadata for an imported object (P6).
|
||||
|
||||
Web-links round-trip fully. File docs are restored as metadata + a blob
|
||||
refcount; the binary itself is not in the JSON export (it rides the
|
||||
/config backup), so unless a matching backup was restored the blob is
|
||||
absent and the hygiene scan flags the doc as dangling. task_ids are
|
||||
dropped (tasks get fresh ids on import). Returns the number created.
|
||||
absent and the hygiene scan flags the doc as dangling. ``task_ids`` /
|
||||
``part_ids`` are remapped through their old→new id maps so a doc's
|
||||
task and spare-part links survive the import; ids with no mapping are
|
||||
dropped. Returns the number created.
|
||||
"""
|
||||
|
||||
def _remap(meta: dict[str, Any]) -> list[str]:
|
||||
if not task_id_map:
|
||||
return []
|
||||
return [task_id_map[t] for t in (meta.get("task_ids") or []) if t in task_id_map]
|
||||
|
||||
def _remap_parts(meta: dict[str, Any]) -> list[str]:
|
||||
if not part_id_map:
|
||||
return []
|
||||
return [part_id_map[p] for p in (meta.get("part_ids") or []) if p in part_id_map]
|
||||
|
||||
created = 0
|
||||
for meta in docs:
|
||||
if not isinstance(meta, dict):
|
||||
@@ -248,7 +275,8 @@ class DocumentStore:
|
||||
"url": url,
|
||||
"title": title or url,
|
||||
"tags": tags,
|
||||
"task_ids": [],
|
||||
"task_ids": _remap(meta),
|
||||
"part_ids": _remap_parts(meta),
|
||||
"added_at": dt_util.utcnow().isoformat(),
|
||||
}
|
||||
created += 1
|
||||
@@ -272,7 +300,8 @@ class DocumentStore:
|
||||
"mime": mime,
|
||||
"size": size,
|
||||
"tags": tags,
|
||||
"task_ids": [],
|
||||
"task_ids": _remap(meta),
|
||||
"part_ids": _remap_parts(meta),
|
||||
"added_at": dt_util.utcnow().isoformat(),
|
||||
}
|
||||
created += 1
|
||||
@@ -292,13 +321,15 @@ class DocumentStore:
|
||||
tags: list[str] | None = None,
|
||||
task_ids: list[str] | None = None,
|
||||
task_pages: dict[str, int] | None = None,
|
||||
part_ids: list[str] | None = None,
|
||||
) -> bool:
|
||||
"""Update editable metadata (title / tags / task links / per-task page).
|
||||
"""Update editable metadata (title / tags / task+part links / per-task page).
|
||||
|
||||
``task_pages`` is a ``{task_id: page}`` map merged into the doc: a page
|
||||
``>= 1`` sets the jump-to page for that task's link, ``0`` clears it. Page
|
||||
hints are always pruned to the currently linked tasks so an unlink also
|
||||
forgets its page, and an empty map is dropped to keep the record clean.
|
||||
``part_ids`` (v2.26) links the doc to spare parts, mirroring task links.
|
||||
"""
|
||||
doc = self.documents.get(doc_id)
|
||||
if doc is None:
|
||||
@@ -309,6 +340,8 @@ class DocumentStore:
|
||||
doc["tags"] = list(tags)
|
||||
if task_ids is not None:
|
||||
doc["task_ids"] = list(task_ids)
|
||||
if part_ids is not None:
|
||||
doc["part_ids"] = list(part_ids)
|
||||
if task_pages is not None:
|
||||
merged = dict(doc.get("task_pages") or {})
|
||||
for tid, page in task_pages.items():
|
||||
|
||||
Reference in New Issue
Block a user