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
2 changes: 0 additions & 2 deletions app/alembic/versions/16a9fa2c1f1e_rename_readonly_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ def upgrade(container: AsyncContainer) -> None: # noqa: ARG001
return

ro_dir.name = READ_ONLY_GROUP_NAME

ro_dir.create_path(ro_dir.parent, ro_dir.get_dn_prefix())

session.execute(
Expand Down Expand Up @@ -91,7 +90,6 @@ def downgrade(container: AsyncContainer) -> None: # noqa: ARG001
return

ro_dir.name = "readonly domain controllers"

ro_dir.create_path(ro_dir.parent, ro_dir.get_dn_prefix())

session.execute(
Expand Down
9 changes: 7 additions & 2 deletions app/alembic/versions/71e642808369_add_directory_is_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,13 @@ async def _indicate_system_directories(
if not base_dn_list:
return

for base_dn in base_dn_list:
base_dn.is_system = True
await session.execute(
update(Directory)
.where(
qa(Directory.parent_id).is_(None),
)
.values(is_system=True),
)

await session.flush()

Expand Down
4 changes: 3 additions & 1 deletion app/ldap_protocol/auth/setup_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
AttributeValueValidator,
)
from ldap_protocol.ldap_schema.entity_type_dao import EntityTypeDAO
from ldap_protocol.utils.async_cache import base_directories_cache
from ldap_protocol.utils.helpers import create_object_sid, generate_domain_sid
from ldap_protocol.utils.queries import get_domain_object_class
from password_utils import PasswordUtils
Expand Down Expand Up @@ -113,6 +114,7 @@ async def setup_enviroment(
domain=domain,
parent=domain,
)
base_directories_cache.clear()

except Exception:
import traceback
Expand All @@ -132,13 +134,13 @@ async def create_dir(
is_system=is_system,
object_class=data["object_class"],
name=data["name"],
parent=parent,
)
dir_.groups = []
dir_.create_path(parent, dir_.get_dn_prefix())

self._session.add(dir_)
await self._session.flush()
dir_.parent_id = parent.id if parent else None
Comment on lines 140 to +143
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

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

The parent_id is set after the flush but before the refresh. If parent is None, this sets parent_id to None. However, the refresh on line 144 only includes "id" in the attribute_names, not "parent_id". If the relationship between parent_id and parent needs to be maintained correctly, consider refreshing both or setting parent_id before the initial flush at line 142.

Suggested change
self._session.add(dir_)
await self._session.flush()
dir_.parent_id = parent.id if parent else None
dir_.parent_id = parent.id if parent else None
self._session.add(dir_)
await self._session.flush()

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Почему то в таком случае parent_id не сохраняется

await self._session.refresh(dir_, ["id"])

self._session.add(
Expand Down
43 changes: 43 additions & 0 deletions app/ldap_protocol/utils/async_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Async cache implementation."""

import time
from functools import wraps
from typing import Callable, Generic, TypeVar

from entities import Directory

T = TypeVar("T")
DEFAULT_CACHE_TIME = 5 * 60 # 5 minutes


class AsyncTTLCache(Generic[T]):
def __init__(self, ttl: int | None = DEFAULT_CACHE_TIME) -> None:
self._ttl = ttl
self._value: T | None = None
self._expires_at: float | None = None

def clear(self) -> None:
self._value = None
self._expires_at = None

def __call__(self, func: Callable) -> Callable:
@wraps(func)
async def wrapper(*args: tuple, **kwargs: dict) -> T:
if self._value is not None:
if not self._expires_at or self._expires_at > time.monotonic():
return self._value
self.clear()

result = await func(*args, **kwargs)

self._value = result
self._expires_at = (
time.monotonic() + self._ttl if self._ttl else None
)

return result

return wrapper


base_directories_cache = AsyncTTLCache[list[Directory]]()
17 changes: 15 additions & 2 deletions app/ldap_protocol/utils/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
queryable_attr as qa,
)

from .async_cache import base_directories_cache
from .const import EMAIL_RE, GRANT_DN_STRING
from .helpers import (
create_integer_hash,
Expand All @@ -35,13 +36,25 @@
)


@base_directories_cache
async def get_base_directories(session: AsyncSession) -> list[Directory]:
"""Get base domain directories."""
result = await session.execute(
select(Directory)
.filter(qa(Directory.parent_id).is_(None)),
) # fmt: skip
return list(result.scalars().all())
res = []
for dir_ in result.scalars():
new_dir = Directory(
**{
k: v
for k, v in dir_.__dict__.items()
Copy link
Collaborator

@Naksen Naksen Jan 22, 2026

Choose a reason for hiding this comment

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

Можно сделать так:

from sqlalchemy import inspect

...

mapper = inspect(dir_).mapper
columns = {col.key for col in mapper.columns} 
new_dir = Directory(**{col: getattr(directory, col) for col in cols})

Только columns сформировать один раз выше цикла

что думаешь ?

Copy link
Collaborator

Choose a reason for hiding this comment

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

ладно, там с id всё равно хрень

if not k.startswith("_") and k != "id"
},
)
new_dir.id = dir_.id
res.append(new_dir)
return res


async def get_user(session: AsyncSession, name: str) -> User | None:
Expand Down Expand Up @@ -362,7 +375,7 @@ async def create_group(
dir_ = Directory(
object_class="",
name=name,
parent=parent,
parent_id=parent.id,
)
session.add(dir_)
await session.flush()
Expand Down
2 changes: 1 addition & 1 deletion interface