Load 1C access profiles groups and users
This commit is contained in:
@@ -106,6 +106,9 @@ _METADATA_OWNER_KINDS = {
|
||||
NodeKind.STYLE_ITEM,
|
||||
NodeKind.STYLE,
|
||||
NodeKind.LANGUAGE,
|
||||
NodeKind.ACCESS_PROFILE,
|
||||
NodeKind.ACCESS_GROUP,
|
||||
NodeKind.ACCESS_USER,
|
||||
NodeKind.XDTO_PACKAGE,
|
||||
NodeKind.EXTENSION,
|
||||
NodeKind.ROLE,
|
||||
@@ -293,6 +296,8 @@ def index_project(path: str | Path, *, project_id: str | None = None, structure_
|
||||
command_nodes: list[SemanticNode] = []
|
||||
form_nodes: list[SemanticNode] = []
|
||||
role_rights: list[dict] = []
|
||||
access_role_assignments: list[dict] = []
|
||||
access_group_memberships: list[dict] = []
|
||||
|
||||
for source_file in source_files:
|
||||
text = _read_text_file(source_file)
|
||||
@@ -400,6 +405,12 @@ def index_project(path: str | Path, *, project_id: str | None = None, structure_
|
||||
if xml_object.object_kind == "RIGHT":
|
||||
role_rights.append(xml_object.attributes)
|
||||
continue
|
||||
if xml_object.object_kind == "ACCESS_ROLE_ASSIGNMENT":
|
||||
access_role_assignments.append(xml_object.attributes)
|
||||
continue
|
||||
if xml_object.object_kind == "ACCESS_GROUP_MEMBERSHIP":
|
||||
access_group_memberships.append(xml_object.attributes)
|
||||
continue
|
||||
kind = _xml_node_kind(xml_object.object_kind)
|
||||
if kind is None:
|
||||
continue
|
||||
@@ -472,6 +483,9 @@ def index_project(path: str | Path, *, project_id: str | None = None, structure_
|
||||
NodeKind.LANGUAGE,
|
||||
NodeKind.XDTO_PACKAGE,
|
||||
NodeKind.EXTENSION,
|
||||
NodeKind.ACCESS_PROFILE,
|
||||
NodeKind.ACCESS_GROUP,
|
||||
NodeKind.ACCESS_USER,
|
||||
NodeKind.ROLE,
|
||||
NodeKind.FORM,
|
||||
NodeKind.TABULAR_SECTION,
|
||||
@@ -480,6 +494,8 @@ def index_project(path: str | Path, *, project_id: str | None = None, structure_
|
||||
|
||||
edges.extend(_link_metadata_to_modules(root, module_nodes, metadata_nodes, form_nodes))
|
||||
edges.extend(_link_role_rights(nodes, role_rights))
|
||||
edges.extend(_link_access_role_assignments(nodes, access_role_assignments))
|
||||
edges.extend(_link_access_group_memberships(nodes, access_group_memberships))
|
||||
edges.extend(_link_scheduled_jobs_to_routines(scheduled_job_nodes, routine_by_name))
|
||||
edges.extend(_link_commands_to_handlers(command_nodes, routine_by_name))
|
||||
edges.extend(_link_forms_to_handlers(form_nodes, routine_by_name))
|
||||
@@ -1109,6 +1125,9 @@ def _xml_node_kind(object_kind: str) -> NodeKind | None:
|
||||
"STYLE_ITEM": NodeKind.STYLE_ITEM,
|
||||
"STYLE": NodeKind.STYLE,
|
||||
"LANGUAGE": NodeKind.LANGUAGE,
|
||||
"ACCESS_PROFILE": NodeKind.ACCESS_PROFILE,
|
||||
"ACCESS_GROUP": NodeKind.ACCESS_GROUP,
|
||||
"ACCESS_USER": NodeKind.ACCESS_USER,
|
||||
"XDTO_PACKAGE": NodeKind.XDTO_PACKAGE,
|
||||
"EXTENSION": NodeKind.EXTENSION,
|
||||
"LAYOUT": NodeKind.LAYOUT,
|
||||
@@ -1313,6 +1332,57 @@ def _link_role_rights(nodes: list[SemanticNode], role_rights: list[dict]) -> lis
|
||||
return edges
|
||||
|
||||
|
||||
def _link_access_role_assignments(nodes: list[SemanticNode], assignments: list[dict]) -> list[SemanticEdge]:
|
||||
if not assignments:
|
||||
return []
|
||||
by_qualified = {_normalize_lookup_key(node.qualified_name): node for node in nodes}
|
||||
by_name_kind = {
|
||||
(node.kind, _normalize_lookup_key(node.name)): node
|
||||
for node in nodes
|
||||
if node.kind in {NodeKind.ACCESS_PROFILE, NodeKind.ACCESS_GROUP, NodeKind.ACCESS_USER, NodeKind.ROLE}
|
||||
}
|
||||
edges: list[SemanticEdge] = []
|
||||
for assignment in assignments:
|
||||
owner_name = str(assignment.get("owner") or assignment.get("profile") or assignment.get("group") or assignment.get("user") or "")
|
||||
role_name = str(assignment.get("role") or assignment.get("Role") or assignment.get("Роль") or "")
|
||||
if not owner_name or not role_name:
|
||||
continue
|
||||
owner = by_qualified.get(_normalize_lookup_key(owner_name)) or next(
|
||||
(
|
||||
by_name_kind.get((kind, _normalize_lookup_key(owner_name)))
|
||||
for kind in (NodeKind.ACCESS_PROFILE, NodeKind.ACCESS_GROUP, NodeKind.ACCESS_USER)
|
||||
if by_name_kind.get((kind, _normalize_lookup_key(owner_name))) is not None
|
||||
),
|
||||
None,
|
||||
)
|
||||
role = by_qualified.get(_normalize_lookup_key(role_name)) or by_qualified.get(_normalize_lookup_key(f"Роль.{role_name}")) or by_name_kind.get((NodeKind.ROLE, _normalize_lookup_key(role_name)))
|
||||
if owner is None or role is None:
|
||||
continue
|
||||
edges.append(_edge(EdgeKind.ASSIGNS_ROLE, owner, role, owner.source_ref.source_path, 1, dict(assignment)))
|
||||
return edges
|
||||
|
||||
|
||||
def _link_access_group_memberships(nodes: list[SemanticNode], memberships: list[dict]) -> list[SemanticEdge]:
|
||||
if not memberships:
|
||||
return []
|
||||
by_qualified = {_normalize_lookup_key(node.qualified_name): node for node in nodes}
|
||||
by_name_kind = {
|
||||
(node.kind, _normalize_lookup_key(node.name)): node
|
||||
for node in nodes
|
||||
if node.kind in {NodeKind.ACCESS_GROUP, NodeKind.ACCESS_USER}
|
||||
}
|
||||
edges: list[SemanticEdge] = []
|
||||
for membership in memberships:
|
||||
group_name = str(membership.get("group") or membership.get("Group") or membership.get("Группа") or "")
|
||||
user_name = str(membership.get("user") or membership.get("User") or membership.get("Пользователь") or "")
|
||||
group = by_qualified.get(_normalize_lookup_key(group_name)) or by_name_kind.get((NodeKind.ACCESS_GROUP, _normalize_lookup_key(group_name)))
|
||||
user = by_qualified.get(_normalize_lookup_key(user_name)) or by_name_kind.get((NodeKind.ACCESS_USER, _normalize_lookup_key(user_name)))
|
||||
if group is None or user is None:
|
||||
continue
|
||||
edges.append(_edge(EdgeKind.MEMBER_OF, user, group, user.source_ref.source_path, 1, dict(membership)))
|
||||
return edges
|
||||
|
||||
|
||||
def _link_scheduled_jobs_to_routines(
|
||||
scheduled_jobs: list[SemanticNode],
|
||||
routine_by_name: dict[str, SemanticNode],
|
||||
|
||||
@@ -107,6 +107,33 @@ def test_index_project_keeps_extended_1c_metadata_objects(tmp_path: Path):
|
||||
}.issubset(by_kind)
|
||||
|
||||
|
||||
def test_index_project_links_access_profiles_groups_and_users(tmp_path: Path):
|
||||
xml = tmp_path / "access.xml"
|
||||
xml.write_text(
|
||||
"""
|
||||
<AccessData>
|
||||
<Role name="ЧтениеПродаж" qualifiedName="Роль.ЧтениеПродаж" />
|
||||
<AccessProfile name="МенеджерПродаж">
|
||||
<Role name="ЧтениеПродаж" />
|
||||
</AccessProfile>
|
||||
<AccessGroup name="ОтделПродаж" profile="МенеджерПродаж">
|
||||
<Member user="ivanov" />
|
||||
</AccessGroup>
|
||||
<InfobaseUser name="ivanov" fullName="Иванов Иван" />
|
||||
</AccessData>
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
snapshot = index_project(tmp_path, project_id="access-graph")
|
||||
|
||||
assert any(node.kind == NodeKind.ACCESS_PROFILE and node.name == "МенеджерПродаж" for node in snapshot.nodes)
|
||||
assert any(node.kind == NodeKind.ACCESS_GROUP and node.name == "ОтделПродаж" for node in snapshot.nodes)
|
||||
assert any(node.kind == NodeKind.ACCESS_USER and node.name == "ivanov" for node in snapshot.nodes)
|
||||
assert any(edge.kind == EdgeKind.ASSIGNS_ROLE for edge in snapshot.edges)
|
||||
assert any(edge.kind == EdgeKind.MEMBER_OF for edge in snapshot.edges)
|
||||
|
||||
|
||||
def test_index_project_remaps_edges_from_duplicate_metadata_nodes(tmp_path: Path):
|
||||
first = tmp_path / "first.xml"
|
||||
first.write_text(
|
||||
|
||||
Reference in New Issue
Block a user