Skip to content
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:
"""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
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 - разница колоссальная

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

стоп, а какая разница name или ldap_display_name?

name проще
ldap_display_name из-за связи через attribute - сложнее, мы вевдь как раз и хотели уйти от связи, но снова к ней возвращаемся

""",
),
)
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated

# 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")
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated


def downgrade(container: AsyncContainer) -> None:
"""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
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated
""",
),
Comment thread
milov-dmitriy marked this conversation as resolved.
)

# 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: 1 addition & 6 deletions app/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ class AccessControlEntry:
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

Expand All @@ -390,12 +391,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
24 changes: 8 additions & 16 deletions app/ldap_protocol/roles/access_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,16 @@ 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)

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:
Expand Down Expand Up @@ -172,7 +172,7 @@ def _check_modify_access(
ace.ace_type == ace_type
and not ace.is_allow
and (
ace.attribute_type_id is None
ace.attribute_type_name is None
or attr_name == ace.attribute_type_name
)
):
Expand All @@ -181,7 +181,7 @@ def _check_modify_access(
ace.ace_type == ace_type
and ace.is_allow
and (
ace.attribute_type_id is None
ace.attribute_type_name is None
or attr_name == ace.attribute_type_name
)
):
Comment thread
milov-dmitriy marked this conversation as resolved.
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
8 changes: 3 additions & 5 deletions app/ldap_protocol/roles/ace_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,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 +95,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 +170,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,
Comment thread
milov-dmitriy marked this conversation as resolved.
directories=directories,
)
Expand Down Expand Up @@ -214,7 +212,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 +238,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
Comment thread
milov-dmitriy marked this conversation as resolved.

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)),
)
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated
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 будет у всех пустой, не?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

  1. зачем если лучше завязываться на обычном name, так проще, написал выше
  2. падажжи. эта миграция идет после переноса в ldap схемы - верно. и именно поэтому все будет ок. либо я не так тебя понял, но я это даже руками тестировал: upgrade и downgrade - все значения корректно туда-сюда переливаются

)
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated
.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
10 changes: 5 additions & 5 deletions app/ldap_protocol/roles/role_use_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ async def create_read_only_role(self) -> None:
ace_type=AceType.READ,
scope=RoleScope.WHOLE_SUBTREE,
base_dn=base_dn_list[0].path_dn,
attribute_type_id=None,
attribute_type_name=None,
entity_type_id=None,
is_allow=True,
)
Expand Down Expand Up @@ -268,7 +268,7 @@ def _get_full_access_aces(
ace_type=AceType.READ,
scope=RoleScope.WHOLE_SUBTREE,
base_dn=base_dn,
attribute_type_id=None,
attribute_type_name=None,
entity_type_id=None,
is_allow=True,
),
Expand All @@ -277,7 +277,7 @@ def _get_full_access_aces(
ace_type=AceType.CREATE_CHILD,
scope=RoleScope.WHOLE_SUBTREE,
base_dn=base_dn,
attribute_type_id=None,
attribute_type_name=None,
entity_type_id=None,
is_allow=True,
),
Expand All @@ -286,7 +286,7 @@ def _get_full_access_aces(
ace_type=AceType.WRITE,
scope=RoleScope.WHOLE_SUBTREE,
base_dn=base_dn,
attribute_type_id=None,
attribute_type_name=None,
entity_type_id=None,
is_allow=True,
),
Expand All @@ -295,7 +295,7 @@ def _get_full_access_aces(
ace_type=AceType.DELETE,
scope=RoleScope.WHOLE_SUBTREE,
base_dn=base_dn,
attribute_type_id=None,
attribute_type_name=None,
entity_type_id=None,
is_allow=True,
),
Expand Down
1 change: 1 addition & 0 deletions app/repo/pg/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ def _compile_create_uc(
nullable=True,
key="attribute_type_id",
),
Column("attribute_type_name", String, nullable=False),
Comment thread
milov-dmitriy marked this conversation as resolved.
Outdated
Column(
"entityTypeId",
Integer,
Expand Down
Loading
Loading