diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py index aedc05a..8a03c4b 100644 --- a/services/api-server/src/api_server/html5.py +++ b/services/api-server/src/api_server/html5.py @@ -324,6 +324,7 @@ def render_html5_object_context( ui: object | None = None, runtime: Iterable[object] | None = None, knowledge: Iterable[object] | None = None, + privacy: object | None = None, ) -> str: if schema is None or impact is None: return f""" @@ -345,6 +346,7 @@ def render_html5_object_context( ui_forms = getattr(ui, "forms", []) if ui is not None else [] runtime_items = list(runtime or []) knowledge_items = list(knowledge or []) + privacy_markers = getattr(privacy, "markers", []) if privacy is not None else [] return f"""
Object context
@@ -361,6 +363,7 @@ def render_html5_object_context( {_metric("Roles", len(grants) or len(roles))} {_metric("Runtime", len(runtime_items))} {_metric("Knowledge", len(knowledge_items))} + {_metric("Privacy", len(privacy_markers))}
{''.join(_named_node_item("attr", item) for item in attributes[:6]) or '

Реквизиты не найдены

'} @@ -369,6 +372,7 @@ def render_html5_object_context( {''.join(_role_access_item(item) for item in grants[:6])} {''.join(_runtime_summary_item(item) for item in runtime_items[:6])} {''.join(_knowledge_record_item(item) for item in knowledge_items[:6])} + {''.join(_privacy_marker_item(item) for item in privacy_markers[:6])} {''.join(_named_node_item("routine", item) for item in routines[:6])} {''.join(_named_node_item("job", item) for item in jobs[:4])}
@@ -1459,6 +1463,18 @@ def _knowledge_record_item(record: object) -> str: """ +def _privacy_marker_item(marker: object) -> str: + classification = _enum_text(getattr(marker, "classification", "")) + reason = str(getattr(marker, "reason", "") or "") + target_id = str(getattr(marker, "target_id", "") or "target unavailable") + return f""" +
+ {escape(classification or "privacy")} + {escape(reason or target_id)} +
+ """ + + def _authoring_diff_item(line: object) -> str: kind = str(getattr(line, "kind", "")) text = str(getattr(line, "text", "")) diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py index 1f5e9d3..678a324 100644 --- a/services/api-server/src/api_server/main.py +++ b/services/api-server/src/api_server/main.py @@ -1747,10 +1747,11 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res impact = await get_object_impact(project_id, object_name) access = await get_object_access(project_id, object_name) ui = await get_object_ui(project_id, object_name) + privacy = await object_privacy(project_id, object_name) runtime = _runtime_for_object_context(project_id, impact) knowledge = _knowledge_for_object_context(schema, impact, ui) return Response( - render_html5_object_context(project_id, schema, impact, access, ui, runtime, knowledge), + render_html5_object_context(project_id, schema, impact, access, ui, runtime, knowledge, privacy), media_type="text/html; charset=utf-8", ) diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py index 0531a8d..2b4e156 100644 --- a/services/api-server/tests/test_api.py +++ b/services/api-server/tests/test_api.py @@ -256,6 +256,7 @@ def test_html5_object_context_fragment(tmp_path: Path): assert indexed.status_code == 200 snapshot = client.get(f"/projects/{project_id}/snapshot/export").json() handler = next(node for node in snapshot["nodes"] if node["name"] == "ПровестиКоманда") + attribute = next(node for node in snapshot["nodes"] if node["name"] == "Контрагент") signal = client.post( f"/projects/{project_id}/runtime/signals", json={ @@ -279,6 +280,15 @@ def test_html5_object_context_fragment(tmp_path: Path): }, ) assert knowledge.status_code == 200 + marker = client.post( + f"/projects/{project_id}/privacy/markers", + json={ + "target_id": attribute["lineage_id"], + "classification": "PERSONAL_DATA", + "reason": "Контрагент содержит персональные данные", + }, + ) + assert marker.status_code == 200 editor = client.get(f"/html5/projects/{project_id}/editor") assert editor.status_code == 200 @@ -301,6 +311,8 @@ def test_html5_object_context_fragment(tmp_path: Path): assert "125.0 ms" in context.text assert "Правила проведения HTML5" in context.text assert "Контекст проведения заказа" in context.text + assert "PERSONAL_DATA" in context.text + assert "Контрагент содержит персональные данные" in context.text assert "Роль.Менеджер" in context.text assert "read, write, post" in context.text or "post, read, write" in context.text assert "