Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
@@ -0,0 +1,71 @@
"""Детерминированный content_hash для сущностей с полем content_hash (sync pull/push)."""
from __future__ import annotations
import hashlib
import json
from typing import Any
# Не входят в хеш: версия/метаданные синка и аудит (иначе хеш «прыгает» без смены данных).
_EXCLUDED_FROM_HASH = frozenset(
{
"version",
"content_hash",
"sync_timestamp",
"sync_status",
"created_at",
"updated_at",
"created_by",
"updated_by",
"client_id",
"server_synced",
"is_deleted",
"deleted_at",
"deleted_by",
"deleted_reason",
"restored_at",
"restored_by",
"restored_reason",
"delete_restore_count",
}
)
def stable_payload_for_hash(data: dict[str, Any]) -> dict[str, Any]:
return {k: v for k, v in data.items() if k not in _EXCLUDED_FROM_HASH}
def compute_content_hash_hex(payload: dict[str, Any]) -> str:
raw = json.dumps(payload, sort_keys=True, ensure_ascii=False, default=str).encode("utf-8")
return hashlib.sha256(raw).hexdigest()
def compute_content_hash_for_object(obj: Any) -> str:
from app.services.sync_record_data import get_object_data
data = get_object_data(obj)
if not isinstance(data, dict):
return ""
stable = stable_payload_for_hash(data)
return compute_content_hash_hex(stable)
def refresh_content_hash_if_applicable(obj: Any) -> None:
if not hasattr(obj, "content_hash"):
return
new_hash = compute_content_hash_for_object(obj)
if new_hash and getattr(obj, "content_hash", None) != new_hash:
obj.content_hash = new_hash
def refresh_content_hashes_for_session(session) -> None:
"""Вызывать из before_flush: новые и изменённые строки с content_hash."""
seen: set[int] = set()
for obj in list(session.new) + list(session.dirty):
oid = id(obj)
if oid in seen:
continue
seen.add(oid)
if not hasattr(obj, "content_hash"):
continue
refresh_content_hash_if_applicable(obj)