98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
"""Portable JSON documents for Writing and Interaction profiles. Not a journal backup."""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from dialogue_store import StoreError
|
|
|
|
FORMAT_VERSION = 1
|
|
KIND_WRITING = "kansho.writing_profile"
|
|
KIND_INTERACTION = "kansho.interaction_profile"
|
|
KIND_BUNDLE = "kansho.profiles"
|
|
ORIGIN_WRITING = {"inferred", "manual", "imported", "accepted_suggestion", "initial_build"}
|
|
ORIGIN_INTERACTION = {"explicit", "manual", "accepted_suggestion"}
|
|
|
|
|
|
def exported_at() -> str:
|
|
return datetime.now(timezone.utc).replace(microsecond=0).isoformat()
|
|
|
|
|
|
def as_document(raw) -> dict:
|
|
if isinstance(raw, str):
|
|
import json
|
|
|
|
try:
|
|
raw = json.loads(raw)
|
|
except json.JSONDecodeError as exc:
|
|
raise StoreError("invalid_document", "JSON ist ungültig.") from exc
|
|
if not isinstance(raw, dict):
|
|
raise StoreError("invalid_document", "Profil-Dokument muss ein JSON-Objekt sein.")
|
|
version = raw.get("format_version", FORMAT_VERSION)
|
|
try:
|
|
version = int(version)
|
|
except (TypeError, ValueError) as exc:
|
|
raise StoreError("unsupported_format", "format_version fehlt oder ist ungültig.") from exc
|
|
if version != FORMAT_VERSION:
|
|
raise StoreError("unsupported_format", f"format_version {version} wird nicht unterstützt.")
|
|
return raw
|
|
|
|
|
|
def writing_payload(document: dict) -> dict:
|
|
data = as_document(document)
|
|
kind = (data.get("kind") or "").strip()
|
|
if kind == KIND_BUNDLE:
|
|
nested = data.get("writing")
|
|
if not isinstance(nested, dict):
|
|
raise StoreError("invalid_document", "Sammeldokument enthält kein Writing Profile.")
|
|
return nested
|
|
if kind != KIND_WRITING:
|
|
raise StoreError("invalid_document", "Das ist kein Writing-Profile-Dokument.")
|
|
return data
|
|
|
|
|
|
def interaction_payload(document: dict) -> dict:
|
|
data = as_document(document)
|
|
kind = (data.get("kind") or "").strip()
|
|
if kind == KIND_BUNDLE:
|
|
nested = data.get("interaction")
|
|
if not isinstance(nested, dict):
|
|
raise StoreError("invalid_document", "Sammeldokument enthält kein Interaction Profile.")
|
|
return nested
|
|
if kind != KIND_INTERACTION:
|
|
raise StoreError("invalid_document", "Das ist kein Interaction-Profile-Dokument.")
|
|
return data
|
|
|
|
|
|
def export_bundle(profile_id: str) -> dict:
|
|
from interaction_profile_store import export_document as export_interaction
|
|
from writing_profile_store import export_document as export_writing
|
|
|
|
writing = export_writing(profile_id)
|
|
interaction = export_interaction(profile_id)
|
|
writing.pop("kind", None)
|
|
writing.pop("format_version", None)
|
|
writing.pop("exported_at", None)
|
|
interaction.pop("kind", None)
|
|
interaction.pop("format_version", None)
|
|
interaction.pop("exported_at", None)
|
|
return {
|
|
"kind": KIND_BUNDLE,
|
|
"format_version": FORMAT_VERSION,
|
|
"exported_at": exported_at(),
|
|
"writing": writing,
|
|
"interaction": interaction,
|
|
}
|
|
|
|
|
|
def restore_bundle(profile_id: str, document: dict) -> dict:
|
|
data = as_document(document)
|
|
kind = (data.get("kind") or "").strip()
|
|
if kind != KIND_BUNDLE:
|
|
raise StoreError("invalid_document", "Das ist kein Sammeldokument beider Profile.")
|
|
from interaction_profile_store import restore_document as restore_interaction
|
|
from writing_profile_store import restore_document as restore_writing
|
|
|
|
writing = restore_writing(profile_id, data)
|
|
interaction = restore_interaction(profile_id, data)
|
|
return {"writing": writing, "interaction": interaction}
|