Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions app/alembic/versions/1b71cafba681_replace_attributeTypeId.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""Delete attributeTypeId add attribute_type_name from AccessControlEntries.
Revision ID: 1b71cafba681
Revises: 708b01eaf025
Create Date: 2026-03-24 16:28:49.116712
"""

import sqlalchemy as sa
from alembic import op
from dishka import AsyncContainer

# revision identifiers, used by Alembic.
revision: None | str = "1b71cafba681"
down_revision: None | str = "708b01eaf025"
branch_labels: None | list[str] = None
depends_on: None | list[str] = None


def upgrade(container: AsyncContainer) -> None: # noqa: ARG001
"""Upgrade."""
op.add_column(
"AccessControlEntries",
sa.Column("attribute_type_name", sa.String(), nullable=True),
)
op.execute(
sa.text(
"""
UPDATE "AccessControlEntries" AS ace
SET attribute_type_name = directory.name
FROM "Directory" AS directory
WHERE ace."attributeTypeId" = directory.id
Comment on lines +29 to +32
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не такой запрос, мы же хотим сделать на ldapDisplayName связь, как жто было до этого. В AccessControlEntry.attribute_type.name лежал твой новый ldap_display_name, а directory.name у того же атрибута, который мы перенесли из таблицы в ldap дерево, может отличаться и сильно. Например, Directory.name = 'Address-Book-Container', а его lDAPDisplayName = addressBookContainer - разница колоссальная

""",
),
)

op.drop_index(
op.f("idx_ace_attribute_type_id"),
table_name="AccessControlEntries",
postgresql_using="hash",
)
op.drop_constraint(
op.f("AccessControlEntries_directoryAttributeTypeId_fkey"),
"AccessControlEntries",
type_="foreignkey",
)
op.drop_column("AccessControlEntries", "attributeTypeId")


def downgrade(container: AsyncContainer) -> None: # noqa: ARG001
"""Downgrade."""
op.add_column(
"AccessControlEntries",
sa.Column(
"attributeTypeId",
sa.INTEGER(),
autoincrement=False,
nullable=True,
),
)

op.execute(
sa.text(
"""
UPDATE "AccessControlEntries" AS ace
SET "attributeTypeId" = directory.id
FROM "Directory" AS directory
WHERE ace.attribute_type_name = directory.name
""",
),
)

op.create_foreign_key(
op.f("AccessControlEntries_directoryAttributeTypeId_fkey"),
"AccessControlEntries",
"Directory",
["attributeTypeId"],
["id"],
ondelete="CASCADE",
)
op.create_index(
op.f("idx_ace_attribute_type_id"),
"AccessControlEntries",
["attributeTypeId"],
unique=False,
postgresql_using="hash",
)
op.drop_column("AccessControlEntries", "attribute_type_name")
7 changes: 7 additions & 0 deletions app/alembic/versions/708b01eaf025_convert_schema_to_ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@

"""

import sqlalchemy as sa
from alembic import op
from dishka import AsyncContainer, Scope
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncSession

from constants import ENTITY_TYPE_DTOS_V2
from extra.alembic_utils import temporary_stub_column
from ldap_protocol.ldap_schema._legacy.attribute_type.attribute_type_use_case import ( # noqa: E501
AttributeTypeUseCaseLegacy,
)
Expand Down Expand Up @@ -124,6 +126,11 @@ async def _rebind_ace_attribute_types_to_directories(
op.run_async(_rebind_ace_attribute_types_to_directories)


@temporary_stub_column(
"AccessControlEntries",
"attribute_type_name",
sa.String(),
)
def downgrade(container: AsyncContainer) -> None:
"""Downgrade."""

Expand Down
13 changes: 1 addition & 12 deletions app/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,16 +370,11 @@ class AccessControlEntry:
role_id: int | None = None
depth: int | None = None
path: str = ""
attribute_type_id: int | None = None
attribute_type_name: str | None = None
entity_type_id: int | None = None
is_allow: bool = False

role: Role | None = field(init=False, default=None, repr=False)
attribute_type: Directory | None = field(
init=False,
default=None,
repr=False,
)
entity_type: EntityType | None = field(
init=False,
default=None,
Expand All @@ -390,12 +385,6 @@ class AccessControlEntry:
repr=False,
)

@property
def attribute_type_name(self) -> str | None:
return (
self.attribute_type.name.lower() if self.attribute_type else None
)

@property
def entity_type_name(self) -> str | None:
return self.entity_type.name if self.entity_type else None
Expand Down
1 change: 0 additions & 1 deletion app/ldap_protocol/ldap_requests/modify.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ async def handle(
user_role_ids=ctx.ldap_session.user.role_ids,
query=query,
ace_types=[AceType.WRITE, AceType.DELETE],
load_attribute_type=True,
)

directory = await ctx.session.scalar(query)
Expand Down
3 changes: 1 addition & 2 deletions app/ldap_protocol/ldap_requests/modify_dn.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ async def handle( # noqa: C901
user_role_ids=ctx.ldap_session.user.role_ids,
query=query,
ace_types=[AceType.DELETE, AceType.WRITE],
load_attribute_type=True,
)

directory = await ctx.session.scalar(query)
Expand Down Expand Up @@ -274,7 +273,7 @@ async def handle( # noqa: C901
for ace in directory.access_control_entries
if (
ace.ace_type == AceType.DELETE
and ace.attribute_type is None
and ace.attribute_type_name is None
)
]

Expand Down
1 change: 0 additions & 1 deletion app/ldap_protocol/ldap_requests/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,6 @@ def _build_query(
user_role_ids=user.role_ids,
query=query,
ace_types=[AceType.READ],
load_attribute_type=True,
)

for base_directory in base_directories:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ async def create(self, dto: AttributeTypeDTO) -> None:
entity_type_name=EntityTypeNames.ATTRIBUTE_TYPE,
attributes=(
AttributeDTO(name=Names.OID, values=[str(dto.oid)]),
AttributeDTO(name=Names.NAME, values=[str(dto.name)]),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

не совсем понял, зачем это удалено

AttributeDTO(
name=Names.OBJECT_CLASS,
values=ATTRIBUTE_TYPE_OBJECT_CLASS_NAMES,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ async def create(self, dto: ObjectClassDTO[None, str]) -> None:
values=OBJECT_CLASS_OBJECT_CLASS_NAMES,
),
AttributeDTO(name=Names.OID, values=[str(dto.oid)]),
AttributeDTO(name=Names.NAME, values=[str(dto.name)]),
AttributeDTO(
name=Names.SUPERIOR_NAME,
values=[str(dto.superior_name)],
Expand Down
30 changes: 11 additions & 19 deletions app/ldap_protocol/roles/access_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,20 @@ def _check_search_access(
return False, set(), set()

for ace in aces:
if not ace.is_allow and ace.attribute_type_id is None:
if not ace.is_allow and ace.attribute_type_name is None:
if allowed_attributes:
return True, set(), allowed_attributes
else:
return False, set(), set()

elif not ace.is_allow and ace.attribute_type_id is not None:
forbidden_attributes.add(ace.attribute_type_name) # type: ignore
elif not ace.is_allow and ace.attribute_type_name is not None:
forbidden_attributes.add(ace.attribute_type_name.lower())

elif ace.is_allow and ace.attribute_type_id is None:
elif ace.is_allow and ace.attribute_type_name is None:
return True, forbidden_attributes, set()

else:
allowed_attributes.add(ace.attribute_type_name) # type: ignore
allowed_attributes.add(ace.attribute_type_name.lower()) # type: ignore

if not allowed_attributes:
return False, set(), set()
Expand Down Expand Up @@ -172,17 +172,17 @@ def _check_modify_access(
ace.ace_type == ace_type
and not ace.is_allow
and (
ace.attribute_type_id is None
or attr_name == ace.attribute_type_name
ace.attribute_type_name is None
or attr_name == ace.attribute_type_name.lower()
)
):
return False
elif (
ace.ace_type == ace_type
and ace.is_allow
and (
ace.attribute_type_id is None
or attr_name == ace.attribute_type_name
ace.attribute_type_name is None
or attr_name == ace.attribute_type_name.lower()
)
):
return True
Expand Down Expand Up @@ -271,7 +271,7 @@ def _extend_user_self_read_ace(
scope=RoleScope.BASE_OBJECT,
is_allow=True,
entity_type_id=None,
attribute_type_id=None,
attribute_type_name=None,
)

if not aces:
Expand All @@ -291,7 +291,6 @@ def mutate_query_with_ace_load(
user_role_ids: list[int],
query: Select[tuple[Directory]],
ace_types: list[AceType],
load_attribute_type: bool = False,
require_attribute_type_null: bool = False,
) -> Select[tuple[Directory]]:
"""Mutate query to load access control entries.
Expand All @@ -312,13 +311,6 @@ def mutate_query_with_ace_load(
base_loader.joinedload(qa(AccessControlEntry.entity_type)),
]

if load_attribute_type:
loader_options.append(
base_loader.joinedload(
qa(AccessControlEntry.attribute_type),
),
)

criteria_conditions = [
qa(AccessControlEntry.role_id).in_(user_role_ids),
]
Expand All @@ -334,7 +326,7 @@ def mutate_query_with_ace_load(

if require_attribute_type_null:
criteria_conditions.append(
qa(AccessControlEntry.attribute_type_id).is_(None),
qa(AccessControlEntry.attribute_type_name).is_(None),
)

return query.options(
Expand Down
12 changes: 3 additions & 9 deletions app/ldap_protocol/roles/ace_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@
lambda x: x.role.name,
P[AccessControlEntryDTO].role_name,
),
link_function(
lambda x: x.attribute_type_id,
P[AccessControlEntryDTO].attribute_type_id,
),
link_function(
lambda x: x.entity_type_id,
P[AccessControlEntryDTO].entity_type_id,
Expand All @@ -66,7 +62,6 @@ async def _get_raw(self, _id: int) -> AccessControlEntry:
query = (
select(AccessControlEntry)
.options(
joinedload(qa(AccessControlEntry.attribute_type)),
joinedload(qa(AccessControlEntry.entity_type)),
joinedload(qa(AccessControlEntry.role)),
selectinload(qa(AccessControlEntry.directories)),
Expand Down Expand Up @@ -96,7 +91,6 @@ async def get_all(self) -> list[AccessControlEntryDTO]:
access_control_entries = (
await self._session.scalars(
select(AccessControlEntry).options(
joinedload(qa(AccessControlEntry.attribute_type)),
joinedload(qa(AccessControlEntry.entity_type)),
joinedload(qa(AccessControlEntry.role)),
),
Expand Down Expand Up @@ -172,7 +166,7 @@ async def create(self, dto: AccessControlEntryDTO) -> None:
path=dto.base_dn,
scope=RoleScope(dto.scope.value),
entity_type_id=dto.entity_type_id,
attribute_type_id=dto.attribute_type_id,
attribute_type_name=dto.attribute_type_name,
is_allow=dto.is_allow,
directories=directories,
)
Expand Down Expand Up @@ -214,7 +208,7 @@ async def create_bulk(self, dtos: list[AccessControlEntryDTO]) -> None:
path=ace.base_dn,
scope=RoleScope(ace.scope.value),
entity_type_id=ace.entity_type_id,
attribute_type_id=ace.attribute_type_id,
attribute_type_name=ace.attribute_type_name,
is_allow=ace.is_allow,
directories=directory_cache[cache_key],
)
Expand All @@ -240,7 +234,7 @@ async def update(self, _id: int, dto: AccessControlEntryDTO) -> None:
ace.role_id = dto.role_id
ace.ace_type = dto.ace_type
ace.entity_type_id = dto.entity_type_id
ace.attribute_type_id = dto.attribute_type_id
ace.attribute_type_name = dto.attribute_type_name
ace.is_allow = dto.is_allow

if dto.scope != ace.scope or dto.base_dn != ace.path:
Expand Down
2 changes: 1 addition & 1 deletion app/ldap_protocol/roles/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AccessControlEntryDTO:
scope: RoleScope
base_dn: GRANT_DN_STRING
is_allow: bool
attribute_type_id: int | None
attribute_type_name: str | None
entity_type_id: int | None

id: int | None = None
Expand Down
11 changes: 6 additions & 5 deletions app/ldap_protocol/roles/migrations_ace_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ async def _get_all_raw_aces_legacy(self) -> Sequence[Row[tuple[int, str]]]:
select(qa(AccessControlEntry.id), qa(AttributeTypeLegacy.name))
.join(
AttributeTypeLegacy,
qa(AccessControlEntry.attribute_type_id)
== qa(AttributeTypeLegacy.id),
qa(AccessControlEntry.attribute_type_name)
== qa(AttributeTypeLegacy.name),
)
.where(qa(AccessControlEntry.attribute_type_id).is_not(None)),
.where(qa(AccessControlEntry.attribute_type_name).is_not(None)),
)
return ace_rows_q.all()

Expand Down Expand Up @@ -102,13 +102,14 @@ async def _get_all_raw_aces(self) -> Sequence[Row[tuple[int, str]]]:
select(qa(AccessControlEntry.id), qa(Directory.name))
.join(
Directory,
qa(AccessControlEntry.attribute_type_id) == qa(Directory.id),
qa(AccessControlEntry.attribute_type_name)
== qa(Directory.name),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. не по directory.name
  2. у тебя изменение ролевки будет после переноса в ldap схемы, если я правильно уловил, т.е. на момент вызова миграции с переносом AccessControlEntry.attribute_type_name будет у всех пустой, не?

)
.join(
EntityType,
qa(EntityType.id) == qa(Directory.entity_type_id),
)
.where(qa(EntityType.name) == EntityTypeNames.ATTRIBUTE_TYPE)
.where(qa(AccessControlEntry.attribute_type_id).is_not(None)),
.where(qa(AccessControlEntry.attribute_type_name).is_not(None)),
)
return ace_rows_q.all()
2 changes: 0 additions & 2 deletions app/ldap_protocol/roles/role_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ async def _get_raw(self, _id: int) -> Role:
qa(Group.directory),
),
selectinload(qa(Role.access_control_entries)).options(
joinedload(qa(AccessControlEntry.attribute_type)),
joinedload(qa(AccessControlEntry.entity_type)),
joinedload(qa(AccessControlEntry.role)),
),
Expand Down Expand Up @@ -108,7 +107,6 @@ async def get_by_name(self, role_name: str) -> RoleDTO:
qa(Group.directory),
),
selectinload(qa(Role.access_control_entries)).options(
joinedload(qa(AccessControlEntry.attribute_type)),
joinedload(qa(AccessControlEntry.entity_type)),
joinedload(qa(AccessControlEntry.role)),
),
Expand Down
Loading
Loading