2026-05-22 15:47:48 +05:30
|
|
|
import threading
|
|
|
|
|
import uuid
|
2026-06-09 10:39:45 +05:30
|
|
|
from datetime import UTC, datetime
|
2026-06-08 11:22:41 +05:30
|
|
|
from typing import Any
|
|
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
|
2026-06-12 15:04:09 +05:30
|
|
|
def extract_permissions(doc_instance: Any) -> dict[str, Any] | None:
|
|
|
|
|
"""Read the engine's DocumentPermissions off a doc into a plain dict, or None
|
|
|
|
|
if unavailable (treated downstream as unrestricted)."""
|
|
|
|
|
try:
|
|
|
|
|
p = doc_instance.permissions
|
|
|
|
|
return {
|
|
|
|
|
"isEncrypted": p.is_encrypted,
|
|
|
|
|
"encryption": p.encryption,
|
|
|
|
|
"securityRevision": p.security_revision,
|
|
|
|
|
"ownerUnlocked": p.owner_unlocked,
|
|
|
|
|
"canPrint": p.can_print,
|
|
|
|
|
"canPrintHighRes": p.can_print_high_res,
|
|
|
|
|
"canModify": p.can_modify,
|
|
|
|
|
"canCopy": p.can_copy,
|
|
|
|
|
"canAnnotate": p.can_annotate,
|
|
|
|
|
"canFillForms": p.can_fill_forms,
|
|
|
|
|
"canExtractForAccessibility": p.can_extract_for_accessibility,
|
|
|
|
|
"canAssemble": p.can_assemble,
|
|
|
|
|
}
|
|
|
|
|
except Exception:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
class DocumentStore:
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self._lock = threading.Lock()
|
2026-06-08 11:22:41 +05:30
|
|
|
self._documents: dict[str, dict[str, Any]] = {}
|
2026-05-22 15:47:48 +05:30
|
|
|
|
2026-06-12 15:04:09 +05:30
|
|
|
def add_document(
|
|
|
|
|
self,
|
|
|
|
|
filename: str,
|
|
|
|
|
bytes_data: bytes,
|
|
|
|
|
doc_instance: Any,
|
|
|
|
|
permissions: dict[str, Any] | None = None,
|
|
|
|
|
) -> dict[str, Any]:
|
2026-05-22 15:47:48 +05:30
|
|
|
doc_id = str(uuid.uuid4())
|
2026-06-08 11:22:41 +05:30
|
|
|
uploaded_at = datetime.now(UTC).isoformat().replace("+00:00", "Z")
|
2026-06-08 11:22:15 +05:30
|
|
|
page_width = 612.0
|
|
|
|
|
page_height = 792.0
|
|
|
|
|
if doc_instance.page_count > 0:
|
|
|
|
|
try:
|
|
|
|
|
page_0 = doc_instance.get_page(0)
|
|
|
|
|
page_width = page_0.width
|
|
|
|
|
page_height = page_0.height
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
2026-06-12 15:04:09 +05:30
|
|
|
# Permissions are computed from the freshly-loaded doc at upload; on derived
|
|
|
|
|
# docs (post-edit, which are saved decrypted) the caller passes the original's
|
|
|
|
|
# permissions forward so enforcement stays consistent.
|
|
|
|
|
if permissions is None:
|
|
|
|
|
permissions = extract_permissions(doc_instance)
|
|
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
info = {
|
|
|
|
|
"id": doc_id,
|
|
|
|
|
"filename": filename,
|
|
|
|
|
"sizeBytes": len(bytes_data),
|
|
|
|
|
"totalPages": doc_instance.page_count,
|
2026-06-08 11:22:15 +05:30
|
|
|
"pageWidth": page_width,
|
|
|
|
|
"pageHeight": page_height,
|
2026-05-22 15:47:48 +05:30
|
|
|
"uploadedAt": uploaded_at,
|
|
|
|
|
"status": "ready",
|
|
|
|
|
"doc_instance": doc_instance,
|
2026-06-08 11:22:41 +05:30
|
|
|
"bytes_data": bytes_data,
|
2026-06-12 15:04:09 +05:30
|
|
|
"permissions": permissions,
|
2026-05-22 15:47:48 +05:30
|
|
|
}
|
2026-06-08 11:22:41 +05:30
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
with self._lock:
|
|
|
|
|
self._documents[doc_id] = info
|
2026-06-08 11:22:41 +05:30
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
return info
|
|
|
|
|
|
2026-06-08 11:22:41 +05:30
|
|
|
def get_document(self, doc_id: str) -> dict[str, Any] | None:
|
2026-05-22 15:47:48 +05:30
|
|
|
with self._lock:
|
|
|
|
|
return self._documents.get(doc_id)
|
|
|
|
|
|
2026-06-08 11:22:41 +05:30
|
|
|
def list_documents(self) -> list[dict[str, Any]]:
|
2026-05-22 15:47:48 +05:30
|
|
|
with self._lock:
|
|
|
|
|
return list(self._documents.values())
|
|
|
|
|
|
|
|
|
|
def delete_document(self, doc_id: str) -> bool:
|
|
|
|
|
with self._lock:
|
|
|
|
|
if doc_id in self._documents:
|
|
|
|
|
del self._documents[doc_id]
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
2026-06-08 11:22:41 +05:30
|
|
|
|
2026-05-22 15:47:48 +05:30
|
|
|
document_store = DocumentStore()
|