Add HTML5 object access context
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-17 00:04:12 +03:00
parent f20c045de9
commit a8baa2aa49
3 changed files with 34 additions and 3 deletions
+27 -2
View File
@@ -316,7 +316,12 @@ def render_html5_review(project_id: str, findings: list[dict] | None) -> str:
""" """
def render_html5_object_context(project_id: str, schema: object | None, impact: object | None) -> str: def render_html5_object_context(
project_id: str,
schema: object | None,
impact: object | None,
access: object | None = None,
) -> str:
if schema is None or impact is None: if schema is None or impact is None:
return f""" return f"""
<div class="object-context" data-html5-object-context> <div class="object-context" data-html5-object-context>
@@ -333,6 +338,7 @@ def render_html5_object_context(project_id: str, schema: object | None, impact:
forms = getattr(impact, "forms", []) or [] forms = getattr(impact, "forms", []) or []
roles = getattr(impact, "roles", []) or [] roles = getattr(impact, "roles", []) or []
jobs = getattr(impact, "jobs", []) or [] jobs = getattr(impact, "jobs", []) or []
grants = getattr(access, "grants", []) if access is not None else []
return f""" return f"""
<div class="object-context" data-html5-object-context data-html5-object-name="{escape(str(name))}"> <div class="object-context" data-html5-object-context data-html5-object-name="{escape(str(name))}">
<div class="panel-title">Object context</div> <div class="panel-title">Object context</div>
@@ -346,11 +352,12 @@ def render_html5_object_context(project_id: str, schema: object | None, impact:
{_metric("Modules", len(modules))} {_metric("Modules", len(modules))}
{_metric("Routines", len(routines))} {_metric("Routines", len(routines))}
{_metric("Forms", len(forms))} {_metric("Forms", len(forms))}
{_metric("Roles", len(roles))} {_metric("Roles", len(grants) or len(roles))}
</dl> </dl>
<div class="compact-list"> <div class="compact-list">
{''.join(_named_node_item("attr", item) for item in attributes[:6]) or '<p class="muted padded">Реквизиты не найдены</p>'} {''.join(_named_node_item("attr", item) for item in attributes[:6]) or '<p class="muted padded">Реквизиты не найдены</p>'}
{''.join(_tabular_section_item(item) for item in sections[:4])} {''.join(_tabular_section_item(item) for item in sections[:4])}
{''.join(_role_access_item(item) for item in grants[:6])}
{''.join(_named_node_item("routine", item) for item in routines[:6])} {''.join(_named_node_item("routine", item) for item in routines[:6])}
{''.join(_named_node_item("job", item) for item in jobs[:4])} {''.join(_named_node_item("job", item) for item in jobs[:4])}
</div> </div>
@@ -1366,6 +1373,24 @@ def _tabular_section_item(section: object) -> str:
""" """
def _role_access_item(grant: object) -> str:
role = getattr(grant, "role", None)
permissions = getattr(grant, "permissions", {}) or {}
role_name = getattr(role, "qualified_name", None) or getattr(role, "name", "role")
enabled = [
str(key)
for key, value in sorted(permissions.items())
if str(value).lower() in {"true", "1", "yes", "да"}
]
permission_text = ", ".join(enabled) if enabled else "permissions unavailable"
return f"""
<article class="object-context-item" data-html5-object-context-item="role-access">
<strong>{escape(str(role_name))}</strong>
<small>{escape(permission_text)}</small>
</article>
"""
def _authoring_diff_item(line: object) -> str: def _authoring_diff_item(line: object) -> str:
kind = str(getattr(line, "kind", "")) kind = str(getattr(line, "kind", ""))
text = str(getattr(line, "text", "")) text = str(getattr(line, "text", ""))
+2 -1
View File
@@ -1745,8 +1745,9 @@ async def html5_project_review(project_id: str) -> Response:
async def html5_project_object_context(project_id: str, object_name: str) -> Response: async def html5_project_object_context(project_id: str, object_name: str) -> Response:
schema = await get_object_schema(project_id, object_name) schema = await get_object_schema(project_id, object_name)
impact = await get_object_impact(project_id, object_name) impact = await get_object_impact(project_id, object_name)
access = await get_object_access(project_id, object_name)
return Response( return Response(
render_html5_object_context(project_id, schema, impact), render_html5_object_context(project_id, schema, impact, access),
media_type="text/html; charset=utf-8", media_type="text/html; charset=utf-8",
) )
+5
View File
@@ -238,6 +238,9 @@ def test_html5_object_context_fragment(tmp_path: Path):
<Attribute name="Количество" qualifiedName="Документ.ЗаказПокупателя.Товары.Количество" /> <Attribute name="Количество" qualifiedName="Документ.ЗаказПокупателя.Товары.Количество" />
</TabularSection> </TabularSection>
</Document> </Document>
<Role name="Менеджер" qualifiedName="Роль.Менеджер">
<Right object="Документ.ЗаказПокупателя" read="true" write="true" post="true" />
</Role>
</Configuration> </Configuration>
""", """,
encoding="utf-8", encoding="utf-8",
@@ -259,6 +262,8 @@ def test_html5_object_context_fragment(tmp_path: Path):
assert "Документ.ЗаказПокупателя" in context.text assert "Документ.ЗаказПокупателя" in context.text
assert "Контрагент" in context.text assert "Контрагент" in context.text
assert "Товары" 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 "<html" not in context.text assert "<html" not in context.text