refactor: ruff autofixes

This commit is contained in:
Mark Paronyan committed 2026-09-27 15:55:10 +03:00
1 parent 2ac637c662
commit a0450b6bce
455 files changed
+12322 -14762

No files matched your search

+4 -21
View File
@@ -30,7 +30,6 @@ log = logging.getLogger(__name__)
class ApiKeysRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -55,11 +54,7 @@ class ApiKeysRepository(BaseRepository):
return result.scalars().first()
async def get_api_keys_by_user(self, user_id: UUID) -> List[models.ApiKey]:
query = (
select(models.ApiKey)
.where(models.ApiKey.user_id == user_id)
.order_by(models.ApiKey.created_at.desc())
)
query = select(models.ApiKey).where(models.ApiKey.user_id == user_id).order_by(models.ApiKey.created_at.desc())
result = await self._db_session.execute(query)
return list(result.scalars().all())
@@ -69,31 +64,19 @@ class ApiKeysRepository(BaseRepository):
return result.scalars().first()
async def revoke_api_key(self, api_key_id: UUID) -> bool:
query = (
update(models.ApiKey)
.where(models.ApiKey.api_key_id == api_key_id)
.values(revoked=True)
)
query = update(models.ApiKey).where(models.ApiKey.api_key_id == api_key_id).values(revoked=True)
result = await self._db_session.execute(query)
await self._db_session.commit()
return result.rowcount > 0
async def restore_api_key(self, api_key_id: UUID) -> bool:
query = (
update(models.ApiKey)
.where(models.ApiKey.api_key_id == api_key_id)
.values(revoked=False)
)
query = update(models.ApiKey).where(models.ApiKey.api_key_id == api_key_id).values(revoked=False)
result = await self._db_session.execute(query)
await self._db_session.commit()
return result.rowcount > 0
async def update_last_used(self, api_key_id: UUID) -> None:
query = (
update(models.ApiKey)
.where(models.ApiKey.api_key_id == api_key_id)
.values(last_used_at=func.now())
)
query = update(models.ApiKey).where(models.ApiKey.api_key_id == api_key_id).values(last_used_at=func.now())
await self._db_session.execute(query)
await self._db_session.commit()
+1 -4
View File
@@ -27,7 +27,6 @@ from gns3server import schemas
class ComputesRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -72,9 +71,7 @@ class ComputesRepository(BaseRepository):
if compute_update.password is not None:
update_values["password"] = compute_update.password.get_secret_value()
query = update(models.Compute).\
where(models.Compute.compute_id == compute_id).\
values(update_values)
query = update(models.Compute).where(models.Compute.compute_id == compute_id).values(update_values)
await self._db_session.execute(query)
await self._db_session.commit()
+19 -17
View File
@@ -31,7 +31,6 @@ log = logging.getLogger(__name__)
class ImagesRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -43,8 +42,9 @@ class ImagesRepository(BaseRepository):
image_dir, image_name = os.path.split(image_path)
if image_dir:
query = select(models.Image).\
where(models.Image.filename == image_name, models.Image.path.endswith(image_path))
query = select(models.Image).where(
models.Image.filename == image_name, models.Image.path.endswith(image_path)
)
else:
query = select(models.Image).where(models.Image.filename == image_name)
result = await self._db_session.execute(query)
@@ -56,8 +56,9 @@ class ImagesRepository(BaseRepository):
"""
if image_dir:
query = select(models.Image).\
where(models.Image.checksum == checksum, models.Image.path.startswith(image_dir))
query = select(models.Image).where(
models.Image.checksum == checksum, models.Image.path.startswith(image_dir)
)
result = await self._db_session.execute(query)
return result.scalars().one_or_none()
else:
@@ -82,9 +83,7 @@ class ImagesRepository(BaseRepository):
Get all templates that an image belongs to.
"""
query = select(models.Template).\
join(models.Template.images).\
filter(models.Image.image_id == image_id)
query = select(models.Template).join(models.Template.images).filter(models.Image.image_id == image_id)
result = await self._db_session.execute(query)
return result.scalars().all()
@@ -101,7 +100,7 @@ class ImagesRepository(BaseRepository):
image_size=image_size,
path=path,
checksum=checksum,
checksum_algorithm=checksum_algorithm
checksum_algorithm=checksum_algorithm,
)
self._db_session.add(db_image)
@@ -114,9 +113,11 @@ class ImagesRepository(BaseRepository):
Update an image.
"""
query = update(models.Image).\
where(models.Image.path == image_path).\
values(checksum=checksum, checksum_algorithm=checksum_algorithm)
query = (
update(models.Image)
.where(models.Image.path == image_path)
.values(checksum=checksum, checksum_algorithm=checksum_algorithm)
)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -132,9 +133,11 @@ class ImagesRepository(BaseRepository):
image_dir, image_name = os.path.split(image_path)
if image_dir:
query = delete(models.Image).\
where(models.Image.filename == image_name, models.Image.path.endswith(image_path)).\
execution_options(synchronize_session=False)
query = (
delete(models.Image)
.where(models.Image.filename == image_name, models.Image.path.endswith(image_path))
.execution_options(synchronize_session=False)
)
else:
query = delete(models.Image).where(models.Image.filename == image_name)
result = await self._db_session.execute(query)
@@ -146,8 +149,7 @@ class ImagesRepository(BaseRepository):
Prune images not attached to any template.
"""
query = select(models.Image).\
filter(~models.Image.templates.any())
query = select(models.Image).filter(~models.Image.templates.any())
result = await self._db_session.execute(query)
images = result.scalars().all()
images_deleted = 0
+70 -122
View File
@@ -50,44 +50,36 @@ class LLMModelConfigsRepository(BaseRepository):
async def get_user_config(self, config_id: UUID) -> Optional[models.LLMModelConfig]:
"""Get a user's LLM model configuration by ID."""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.user_id.isnot(None)
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.user_id.isnot(None))
)
result = await self._db_session.execute(query)
return result.scalars().first()
async def get_user_configs(self, user_id: UUID) -> List[models.LLMModelConfig]:
"""Get all LLM model configurations for a user."""
query = select(models.LLMModelConfig).where(
models.LLMModelConfig.user_id == user_id
).order_by(models.LLMModelConfig.created_at)
query = (
select(models.LLMModelConfig)
.where(models.LLMModelConfig.user_id == user_id)
.order_by(models.LLMModelConfig.created_at)
)
result = await self._db_session.execute(query)
return result.scalars().all()
async def get_user_default_config(self, user_id: UUID) -> Optional[models.LLMModelConfig]:
"""Get a user's default LLM model configuration."""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.user_id == user_id,
models.LLMModelConfig.is_default
)
and_(models.LLMModelConfig.user_id == user_id, models.LLMModelConfig.is_default)
)
result = await self._db_session.execute(query)
return result.scalars().first()
async def create_user_config(
self,
user_id: UUID,
name: str,
model_type: str,
config_data: Dict[str, Any],
is_default: bool = False
self, user_id: UUID, name: str, model_type: str, config_data: Dict[str, Any], is_default: bool = False
) -> models.LLMModelConfig:
"""Create a new LLM model configuration for a user."""
# Encrypt API key if present
from gns3server.utils.encryption import encrypt
config_to_store = config_data.copy()
if "api_key" in config_to_store and config_to_store["api_key"]:
try:
@@ -105,7 +97,7 @@ class LLMModelConfigsRepository(BaseRepository):
user_id=user_id,
is_default=is_default,
created_at=now,
updated_at=now
updated_at=now,
)
self._db_session.add(db_config)
await self._db_session.commit()
@@ -113,11 +105,7 @@ class LLMModelConfigsRepository(BaseRepository):
return db_config
async def update_user_config(
self,
config_id: UUID,
user_id: UUID,
updates: Dict[str, Any],
expected_version: Optional[int] = None
self, config_id: UUID, user_id: UUID, updates: Dict[str, Any], expected_version: Optional[int] = None
) -> Optional[models.LLMModelConfig]:
"""
Update a user's LLM model configuration.
@@ -130,10 +118,7 @@ class LLMModelConfigsRepository(BaseRepository):
:raises ValueError: If version mismatch (concurrent modification)
"""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.user_id == user_id
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.user_id == user_id)
)
result = await self._db_session.execute(query)
db_config = result.scalars().first()
@@ -193,10 +178,7 @@ class LLMModelConfigsRepository(BaseRepository):
async def delete_user_config(self, config_id: UUID, user_id: UUID) -> bool:
"""Delete a user's LLM model configuration."""
query = delete(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.user_id == user_id
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.user_id == user_id)
)
result = await self._db_session.execute(query)
await self._db_session.commit()
@@ -208,22 +190,16 @@ class LLMModelConfigsRepository(BaseRepository):
# First, unset current default
await self._db_session.execute(
update(models.LLMModelConfig)
.where(
and_(
models.LLMModelConfig.user_id == user_id,
models.LLMModelConfig.is_default
)
)
.where(and_(models.LLMModelConfig.user_id == user_id, models.LLMModelConfig.is_default))
.values(is_default=False, updated_at=now)
)
# Set new default
query = update(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.user_id == user_id
)
).values(is_default=True, updated_at=now)
query = (
update(models.LLMModelConfig)
.where(and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.user_id == user_id))
.values(is_default=True, updated_at=now)
)
result = await self._db_session.execute(query)
await self._db_session.commit()
return result.rowcount > 0
@@ -233,44 +209,36 @@ class LLMModelConfigsRepository(BaseRepository):
async def get_group_config(self, config_id: UUID) -> Optional[models.LLMModelConfig]:
"""Get a group's LLM model configuration by ID."""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.group_id.isnot(None)
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.group_id.isnot(None))
)
result = await self._db_session.execute(query)
return result.scalars().first()
async def get_group_configs(self, group_id: UUID) -> List[models.LLMModelConfig]:
"""Get all LLM model configurations for a group."""
query = select(models.LLMModelConfig).where(
models.LLMModelConfig.group_id == group_id
).order_by(models.LLMModelConfig.created_at)
query = (
select(models.LLMModelConfig)
.where(models.LLMModelConfig.group_id == group_id)
.order_by(models.LLMModelConfig.created_at)
)
result = await self._db_session.execute(query)
return result.scalars().all()
async def get_group_default_config(self, group_id: UUID) -> Optional[models.LLMModelConfig]:
"""Get a group's default LLM model configuration."""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.group_id == group_id,
models.LLMModelConfig.is_default
)
and_(models.LLMModelConfig.group_id == group_id, models.LLMModelConfig.is_default)
)
result = await self._db_session.execute(query)
return result.scalars().first()
async def create_group_config(
self,
group_id: UUID,
name: str,
model_type: str,
config_data: Dict[str, Any],
is_default: bool = False
self, group_id: UUID, name: str, model_type: str, config_data: Dict[str, Any], is_default: bool = False
) -> models.LLMModelConfig:
"""Create a new LLM model configuration for a group."""
# Encrypt API key if present
from gns3server.utils.encryption import encrypt
config_to_store = config_data.copy()
if "api_key" in config_to_store and config_to_store["api_key"]:
try:
@@ -288,7 +256,7 @@ class LLMModelConfigsRepository(BaseRepository):
group_id=group_id,
is_default=is_default,
created_at=now,
updated_at=now
updated_at=now,
)
self._db_session.add(db_config)
await self._db_session.commit()
@@ -296,11 +264,7 @@ class LLMModelConfigsRepository(BaseRepository):
return db_config
async def update_group_config(
self,
config_id: UUID,
group_id: UUID,
updates: Dict[str, Any],
expected_version: Optional[int] = None
self, config_id: UUID, group_id: UUID, updates: Dict[str, Any], expected_version: Optional[int] = None
) -> Optional[models.LLMModelConfig]:
"""
Update a group's LLM model configuration.
@@ -313,10 +277,7 @@ class LLMModelConfigsRepository(BaseRepository):
:raises ValueError: If version mismatch (concurrent modification)
"""
query = select(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.group_id == group_id
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.group_id == group_id)
)
result = await self._db_session.execute(query)
db_config = result.scalars().first()
@@ -376,10 +337,7 @@ class LLMModelConfigsRepository(BaseRepository):
async def delete_group_config(self, config_id: UUID, group_id: UUID) -> bool:
"""Delete a group's LLM model configuration."""
query = delete(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.group_id == group_id
)
and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.group_id == group_id)
)
result = await self._db_session.execute(query)
await self._db_session.commit()
@@ -391,22 +349,16 @@ class LLMModelConfigsRepository(BaseRepository):
# First, unset current default
await self._db_session.execute(
update(models.LLMModelConfig)
.where(
and_(
models.LLMModelConfig.group_id == group_id,
models.LLMModelConfig.is_default
)
)
.where(and_(models.LLMModelConfig.group_id == group_id, models.LLMModelConfig.is_default))
.values(is_default=False, updated_at=now)
)
# Set new default
query = update(models.LLMModelConfig).where(
and_(
models.LLMModelConfig.config_id == config_id,
models.LLMModelConfig.group_id == group_id
)
).values(is_default=True, updated_at=now)
query = (
update(models.LLMModelConfig)
.where(and_(models.LLMModelConfig.config_id == config_id, models.LLMModelConfig.group_id == group_id))
.values(is_default=True, updated_at=now)
)
result = await self._db_session.execute(query)
await self._db_session.commit()
return result.rowcount > 0
@@ -414,10 +366,7 @@ class LLMModelConfigsRepository(BaseRepository):
# Inheritance methods
async def get_user_effective_configs(
self,
user_id: UUID,
current_user_id: Optional[UUID] = None,
current_user_is_superadmin: bool = False
self, user_id: UUID, current_user_id: Optional[UUID] = None, current_user_is_superadmin: bool = False
) -> Dict[str, Any]:
"""
Get user's effective configurations (own + inherited from groups).
@@ -429,9 +378,7 @@ class LLMModelConfigsRepository(BaseRepository):
user_configs = await self.get_user_configs(user_id)
# Get user's groups
query = select(models.UserGroup).\
join(models.UserGroup.users).\
filter(models.User.user_id == user_id)
query = select(models.UserGroup).join(models.UserGroup.users).filter(models.User.user_id == user_id)
result = await self._db_session.execute(query)
user_groups = result.scalars().all()
@@ -453,28 +400,8 @@ class LLMModelConfigsRepository(BaseRepository):
# Always hide API key for security
config_dict = self._hide_api_key(config.config)
configs_with_source.append({
"config_id": config.config_id,
"name": config.name,
"model_type": config.model_type,
"config": config_dict,
"user_id": config.user_id,
"group_id": config.group_id,
"is_default": config.is_default,
"version": config.version,
"created_at": config.created_at,
"updated_at": config.updated_at,
"source": "user",
"group_name": None
})
# Add inherited group configs (always shown, regardless of user configs)
for group_id, configs in group_configs_map.items():
for config in configs:
# Always hide API key for security
config_dict = self._hide_api_key(config.config)
configs_with_source.append({
configs_with_source.append(
{
"config_id": config.config_id,
"name": config.name,
"model_type": config.model_type,
@@ -485,9 +412,33 @@ class LLMModelConfigsRepository(BaseRepository):
"version": config.version,
"created_at": config.created_at,
"updated_at": config.updated_at,
"source": "group",
"group_name": group_names_map[group_id]
})
"source": "user",
"group_name": None,
}
)
# Add inherited group configs (always shown, regardless of user configs)
for group_id, configs in group_configs_map.items():
for config in configs:
# Always hide API key for security
config_dict = self._hide_api_key(config.config)
configs_with_source.append(
{
"config_id": config.config_id,
"name": config.name,
"model_type": config.model_type,
"config": config_dict,
"user_id": config.user_id,
"group_id": config.group_id,
"is_default": config.is_default,
"version": config.version,
"created_at": config.created_at,
"updated_at": config.updated_at,
"source": "group",
"group_name": group_names_map[group_id],
}
)
# Select default_config with proper priority:
# 1. User's config marked with is_default: true
@@ -508,7 +459,4 @@ class LLMModelConfigsRepository(BaseRepository):
if default_config is None and configs_with_source:
default_config = configs_with_source[0]
return {
"configs": configs_with_source,
"default_config": default_config
}
return {"configs": configs_with_source, "default_config": default_config}
+29 -28
View File
@@ -32,7 +32,6 @@ log = logging.getLogger(__name__)
class ResourcePoolsRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -61,9 +60,7 @@ class ResourcePoolsRepository(BaseRepository):
"""
db_resource = models.Resource(
resource_id=resource.resource_id,
resource_type=resource.resource_type,
name=resource.name
resource_id=resource.resource_id, resource_type=resource.resource_type, name=resource.name
)
self._db_session.add(db_resource)
await self._db_session.commit()
@@ -85,9 +82,11 @@ class ResourcePoolsRepository(BaseRepository):
Get all resource memberships in resource pools.
"""
query = select(models.ResourcePool).\
join(models.ResourcePool.resources).\
filter(models.Resource.resource_id == resource_id)
query = (
select(models.ResourcePool)
.join(models.ResourcePool.resources)
.filter(models.Resource.resource_id == resource_id)
)
result = await self._db_session.execute(query)
return result.scalars().all()
@@ -131,18 +130,18 @@ class ResourcePoolsRepository(BaseRepository):
return db_resource_pool
async def update_resource_pool(
self,
resource_pool_id: UUID,
resource_pool_update: schemas.ResourcePoolUpdate
self, resource_pool_id: UUID, resource_pool_update: schemas.ResourcePoolUpdate
) -> Optional[models.ResourcePool]:
"""
Update a resource pool.
"""
update_values = resource_pool_update.model_dump(exclude_unset=True)
query = update(models.ResourcePool).\
where(models.ResourcePool.resource_pool_id == resource_pool_id).\
values(update_values)
query = (
update(models.ResourcePool)
.where(models.ResourcePool.resource_pool_id == resource_pool_id)
.values(update_values)
)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -170,17 +169,17 @@ class ResourcePoolsRepository(BaseRepository):
return result.rowcount > 0
async def add_resource_to_pool(
self,
resource_pool_id: UUID,
resource: models.Resource
self, resource_pool_id: UUID, resource: models.Resource
) -> Union[None, models.ResourcePool]:
"""
Add a resource to a resource pool.
"""
query = select(models.ResourcePool).\
options(selectinload(models.ResourcePool.resources)).\
where(models.ResourcePool.resource_pool_id == resource_pool_id)
query = (
select(models.ResourcePool)
.options(selectinload(models.ResourcePool.resources))
.where(models.ResourcePool.resource_pool_id == resource_pool_id)
)
result = await self._db_session.execute(query)
resource_pool_db = result.scalars().first()
if not resource_pool_db:
@@ -192,17 +191,17 @@ class ResourcePoolsRepository(BaseRepository):
return resource_pool_db
async def remove_resource_from_pool(
self,
resource_pool_id: UUID,
resource: models.Resource
self, resource_pool_id: UUID, resource: models.Resource
) -> Union[None, models.ResourcePool]:
"""
Remove a resource from a resource pool.
"""
query = select(models.ResourcePool).\
options(selectinload(models.ResourcePool.resources)).\
where(models.ResourcePool.resource_pool_id == resource_pool_id)
query = (
select(models.ResourcePool)
.options(selectinload(models.ResourcePool.resources))
.where(models.ResourcePool.resource_pool_id == resource_pool_id)
)
result = await self._db_session.execute(query)
resource_pool_db = result.scalars().first()
if not resource_pool_db:
@@ -219,9 +218,11 @@ class ResourcePoolsRepository(BaseRepository):
Get all resources from a resource pool.
"""
query = select(models.Resource).\
join(models.Resource.resource_pools).\
filter(models.ResourcePool.resource_pool_id == resource_pool_id)
query = (
select(models.Resource)
.join(models.Resource.resource_pools)
.filter(models.ResourcePool.resource_pool_id == resource_pool_id)
)
result = await self._db_session.execute(query)
return result.scalars().all()
+52 -83
View File
@@ -33,7 +33,6 @@ log = logging.getLogger(__name__)
class RbacRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -43,9 +42,7 @@ class RbacRepository(BaseRepository):
Get a role by its ID.
"""
query = select(models.Role).\
options(selectinload(models.Role.privileges)).\
where(models.Role.role_id == role_id)
query = select(models.Role).options(selectinload(models.Role.privileges)).where(models.Role.role_id == role_id)
result = await self._db_session.execute(query)
return result.scalars().first()
@@ -54,9 +51,7 @@ class RbacRepository(BaseRepository):
Get a role by its name.
"""
query = select(models.Role).\
options(selectinload(models.Role.privileges)).\
where(models.Role.name == name)
query = select(models.Role).options(selectinload(models.Role.privileges)).where(models.Role.name == name)
result = await self._db_session.execute(query)
return result.scalars().first()
@@ -82,19 +77,13 @@ class RbacRepository(BaseRepository):
await self._db_session.commit()
return await self.get_role(db_role.role_id)
async def update_role(
self,
role_id: UUID,
role_update: schemas.RoleUpdate
) -> Optional[models.Role]:
async def update_role(self, role_id: UUID, role_update: schemas.RoleUpdate) -> Optional[models.Role]:
"""
Update a role.
"""
update_values = role_update.model_dump(exclude_unset=True)
query = update(models.Role).\
where(models.Role.role_id == role_id).\
values(update_values)
query = update(models.Role).where(models.Role.role_id == role_id).values(update_values)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -113,18 +102,12 @@ class RbacRepository(BaseRepository):
await self._db_session.commit()
return result.rowcount > 0
async def add_privilege_to_role(
self,
role_id: UUID,
privilege: models.Privilege
) -> Union[None, models.Role]:
async def add_privilege_to_role(self, role_id: UUID, privilege: models.Privilege) -> Union[None, models.Role]:
"""
Add a privilege to a role.
"""
query = select(models.Role).\
options(selectinload(models.Role.privileges)).\
where(models.Role.role_id == role_id)
query = select(models.Role).options(selectinload(models.Role.privileges)).where(models.Role.role_id == role_id)
result = await self._db_session.execute(query)
role_db = result.scalars().first()
if not role_db:
@@ -142,18 +125,12 @@ class RbacRepository(BaseRepository):
await self._db_session.refresh(role_db)
return role_db
async def remove_privilege_from_role(
self,
role_id: UUID,
privilege: models.Privilege
) -> Union[None, models.Role]:
async def remove_privilege_from_role(self, role_id: UUID, privilege: models.Privilege) -> Union[None, models.Role]:
"""
Remove a privilege from a role.
"""
query = select(models.Role).\
options(selectinload(models.Role.privileges)).\
where(models.Role.role_id == role_id)
query = select(models.Role).options(selectinload(models.Role.privileges)).where(models.Role.role_id == role_id)
result = await self._db_session.execute(query)
role_db = result.scalars().first()
if not role_db:
@@ -169,9 +146,7 @@ class RbacRepository(BaseRepository):
Get all the role privileges.
"""
query = select(models.Privilege).\
join(models.Privilege.roles).\
filter(models.Role.role_id == role_id)
query = select(models.Privilege).join(models.Privilege.roles).filter(models.Role.role_id == role_id)
result = await self._db_session.execute(query)
return result.scalars().all()
@@ -237,15 +212,11 @@ class RbacRepository(BaseRepository):
This method includes related user, group, and role information.
"""
query = select(models.ACE).\
where(
(models.ACE.path == path) | (models.ACE.path.startswith(path + "/"))
).\
options(
selectinload(models.ACE.user),
selectinload(models.ACE.group),
selectinload(models.ACE.role)
)
query = (
select(models.ACE)
.where((models.ACE.path == path) | (models.ACE.path.startswith(path + "/")))
.options(selectinload(models.ACE.user), selectinload(models.ACE.group), selectinload(models.ACE.role))
)
result = await self._db_session.execute(query)
return result.scalars().all()
@@ -254,8 +225,7 @@ class RbacRepository(BaseRepository):
Check if an ACE exists.
"""
query = select(models.ACE).\
where(models.ACE.path == path)
query = select(models.ACE).where(models.ACE.path == path)
result = await self._db_session.execute(query)
return result.scalars().first() is not None
@@ -271,19 +241,13 @@ class RbacRepository(BaseRepository):
await self._db_session.refresh(db_ace)
return db_ace
async def update_ace(
self,
ace_id: UUID,
ace_update: schemas.ACEUpdate
) -> Optional[models.ACE]:
async def update_ace(self, ace_id: UUID, ace_update: schemas.ACEUpdate) -> Optional[models.ACE]:
"""
Update an ACE
"""
update_values = ace_update.model_dump(exclude_unset=True)
query = update(models.ACE).\
where(models.ACE.ace_id == ace_id).\
values(update_values)
query = update(models.ACE).where(models.ACE.ace_id == ace_id).values(update_values)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -307,9 +271,7 @@ class RbacRepository(BaseRepository):
Delete all ACEs starting with path.
"""
query = delete(models.ACE).\
where(models.ACE.path.startswith(path)).\
execution_options(synchronize_session=False)
query = delete(models.ACE).where(models.ACE.path.startswith(path)).execution_options(synchronize_session=False)
result = await self._db_session.execute(query)
log.debug(f"{result.rowcount} ACE(s) have been deleted")
@@ -344,9 +306,11 @@ class RbacRepository(BaseRepository):
for ace_path, ace_propagate, ace_allowed, ace_privilege in aces:
if ace_path.startswith("/pool"):
resource_pool_id = ace_path.split("/")[2]
query = select(models.Resource). \
join(models.Resource.resource_pools). \
filter(models.ResourcePool.resource_pool_id == resource_pool_id)
query = (
select(models.Resource)
.join(models.Resource.resource_pools)
.filter(models.ResourcePool.resource_pool_id == resource_pool_id)
)
result = await self._db_session.execute(query)
resources = result.scalars().all()
@@ -366,13 +330,15 @@ class RbacRepository(BaseRepository):
Retrieve all user ACEs matching the user_id and privilege name.
"""
query = select(models.ACE.path, models.ACE.propagate, models.ACE.allowed, models.Privilege.name).\
join(models.Privilege.roles).\
join(models.Role.acl_entries).\
join(models.ACE.user). \
filter(models.User.user_id == user_id).\
filter(models.Privilege.name == privilege_name).\
order_by(models.ACE.path.desc())
query = (
select(models.ACE.path, models.ACE.propagate, models.ACE.allowed, models.Privilege.name)
.join(models.Privilege.roles)
.join(models.Role.acl_entries)
.join(models.ACE.user)
.filter(models.User.user_id == user_id)
.filter(models.Privilege.name == privilege_name)
.order_by(models.ACE.path.desc())
)
result = await self._db_session.execute(query)
return result.all()
@@ -382,13 +348,15 @@ class RbacRepository(BaseRepository):
Retrieve all group ACEs matching the user_id and privilege name.
"""
query = select(models.ACE.path, models.ACE.propagate, models.ACE.allowed, models.Privilege.name). \
join(models.Privilege.roles). \
join(models.Role.acl_entries). \
join(models.ACE.group). \
join(models.UserGroup.users).\
filter(models.User.user_id == user_id). \
filter(models.Privilege.name == privilege_name)
query = (
select(models.ACE.path, models.ACE.propagate, models.ACE.allowed, models.Privilege.name)
.join(models.Privilege.roles)
.join(models.Role.acl_entries)
.join(models.ACE.group)
.join(models.UserGroup.users)
.filter(models.User.user_id == user_id)
.filter(models.Privilege.name == privilege_name)
)
result = await self._db_session.execute(query)
return result.all()
@@ -404,12 +372,7 @@ class RbacRepository(BaseRepository):
pool_resources.extend(await self._get_resources_in_pools(group_aces))
return list(set(pool_resources))
async def get_accessible_project_ids(
self,
user_id: UUID,
privilege_name: str,
all_project_ids: List[str]
):
async def get_accessible_project_ids(self, user_id: UUID, privilege_name: str, all_project_ids: List[str]):
"""
Batch check which projects a user can access via direct ACE or resource pools.
Performs 3 fixed DB queries regardless of project count.
@@ -448,8 +411,11 @@ class RbacRepository(BaseRepository):
user_denied.add(pid)
# --- User ACE: pool check ---
user_pool_ids = {ace_path.split("/")[2] for ace_path, _, ace_allowed, _ in user_aces
if ace_path.startswith("/pools/") and ace_allowed}
user_pool_ids = {
ace_path.split("/")[2]
for ace_path, _, ace_allowed, _ in user_aces
if ace_path.startswith("/pools/") and ace_allowed
}
pool_accessible_ids = set()
for pool_id, project_ids in pool_to_projects.items():
@@ -470,8 +436,11 @@ class RbacRepository(BaseRepository):
pass
# --- Group ACE: pool check ---
group_pool_ids = {ace_path.split("/")[2] for ace_path, _, ace_allowed, _ in group_aces
if ace_path.startswith("/pools/") and ace_allowed}
group_pool_ids = {
ace_path.split("/")[2]
for ace_path, _, ace_allowed, _ in group_aces
if ace_path.startswith("/pools/") and ace_allowed
}
for pool_id, project_ids in pool_to_projects.items():
if pool_id in group_pool_ids:
+34 -34
View File
@@ -47,7 +47,6 @@ TEMPLATE_TYPE_TO_MODEL = {
class TemplatesRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -57,17 +56,21 @@ class TemplatesRepository(BaseRepository):
async def get_template(self, template_id: UUID) -> Union[None, models.Template]:
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.template_id == template_id)
query = (
select(models.Template)
.options(selectinload(models.Template.images))
.where(models.Template.template_id == template_id)
)
result = await self._db_session.execute(query)
return result.scalars().first()
async def get_template_by_name_and_version(self, name: str, version: str) -> Union[None, models.Template]:
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.name == name, models.Template.version == version)
query = (
select(models.Template)
.options(selectinload(models.Template.images))
.where(models.Template.name == name, models.Template.version == version)
)
result = await self._db_session.execute(query)
return result.scalars().first()
@@ -76,9 +79,9 @@ class TemplatesRepository(BaseRepository):
Return the first template with this name, regardless of version.
"""
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.name == name)
query = (
select(models.Template).options(selectinload(models.Template.images)).where(models.Template.name == name)
)
result = await self._db_session.execute(query)
return result.scalars().first()
@@ -115,9 +118,11 @@ class TemplatesRepository(BaseRepository):
async def duplicate_template(self, template_id: UUID) -> Optional[schemas.Template]:
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.template_id == template_id)
query = (
select(models.Template)
.options(selectinload(models.Template.images))
.where(models.Template.template_id == template_id)
)
db_template = (await self._db_session.execute(query)).scalars().first()
if db_template:
# duplicate db object with new primary key (template_id)
@@ -136,8 +141,9 @@ class TemplatesRepository(BaseRepository):
image_dir, image_name = os.path.split(image_path)
if image_dir:
query = select(models.Image).\
where(models.Image.filename == image_name, models.Image.path.endswith(image_path))
query = select(models.Image).where(
models.Image.filename == image_name, models.Image.path.endswith(image_path)
)
else:
query = select(models.Image).where(models.Image.filename == image_name)
query = query.order_by(models.Image.image_id)
@@ -151,18 +157,16 @@ class TemplatesRepository(BaseRepository):
)
return images[0] if images else None
async def add_image_to_template(
self,
template_id: UUID,
image: models.Image
) -> Union[None, models.Template]:
async def add_image_to_template(self, template_id: UUID, image: models.Image) -> Union[None, models.Template]:
"""
Add an image to template.
"""
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.template_id == template_id)
query = (
select(models.Template)
.options(selectinload(models.Template.images))
.where(models.Template.template_id == template_id)
)
result = await self._db_session.execute(query)
template_in_db = result.scalars().first()
if not template_in_db:
@@ -173,18 +177,16 @@ class TemplatesRepository(BaseRepository):
await self._db_session.refresh(template_in_db)
return template_in_db
async def remove_image_from_template(
self,
template_id: UUID,
image: models.Image
) -> Union[None, models.Template]:
async def remove_image_from_template(self, template_id: UUID, image: models.Image) -> Union[None, models.Template]:
"""
Remove an image from a template.
"""
query = select(models.Template).\
options(selectinload(models.Template.images)).\
where(models.Template.template_id == template_id)
query = (
select(models.Template)
.options(selectinload(models.Template.images))
.where(models.Template.template_id == template_id)
)
result = await self._db_session.execute(query)
template_in_db = result.scalars().first()
if not template_in_db:
@@ -201,8 +203,6 @@ class TemplatesRepository(BaseRepository):
Return all images attached to a template.
"""
query = select(models.Image).\
join(models.Image.templates).\
filter(models.Template.template_id == template_id)
query = select(models.Image).join(models.Image.templates).filter(models.Template.template_id == template_id)
result = await self._db_session.execute(query)
return result.scalars().all()
+26 -39
View File
@@ -33,7 +33,6 @@ log = logging.getLogger(__name__)
class UsersRepository(BaseRepository):
def __init__(self, db_session: AsyncSession) -> None:
super().__init__(db_session)
@@ -82,10 +81,7 @@ class UsersRepository(BaseRepository):
hashed_password = self._auth_service.hash_password(user.password.get_secret_value())
db_user = models.User(
username=user.username,
email=user.email,
full_name=user.full_name,
hashed_password=hashed_password
username=user.username, email=user.email, full_name=user.full_name, hashed_password=hashed_password
)
self._db_session.add(db_user)
await self._db_session.commit()
@@ -102,9 +98,7 @@ class UsersRepository(BaseRepository):
if password:
update_values["hashed_password"] = self._auth_service.hash_password(password=password.get_secret_value())
query = update(models.User).\
where(models.User.user_id == user_id).\
values(update_values)
query = update(models.User).where(models.User.user_id == user_id).values(update_values)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -118,9 +112,11 @@ class UsersRepository(BaseRepository):
Increment token_version to invalidate all existing tokens for the user.
"""
query = update(models.User).\
where(models.User.user_id == user_id).\
values(token_version=models.User.token_version + 1)
query = (
update(models.User)
.where(models.User.user_id == user_id)
.values(token_version=models.User.token_version + 1)
)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -147,8 +143,9 @@ class UsersRepository(BaseRepository):
# this is useful for manual password recovery like:
# sqlite3 gns3_controller.db "UPDATE users SET hashed_password = null WHERE username = 'admin';"
if user.hashed_password is None:
log.warning(f"User '{username}' has been authenticated without a password "
f"configured. Please set a new password.")
log.warning(
f"User '{username}' has been authenticated without a password configured. Please set a new password."
)
return user
if not self._auth_service.verify_password(password, user.hashed_password):
return None
@@ -168,9 +165,7 @@ class UsersRepository(BaseRepository):
Get all user memberships (user groups).
"""
query = select(models.UserGroup).\
join(models.UserGroup.users).\
filter(models.User.user_id == user_id)
query = select(models.UserGroup).join(models.UserGroup.users).filter(models.User.user_id == user_id)
result = await self._db_session.execute(query)
return result.scalars().all()
@@ -214,18 +209,14 @@ class UsersRepository(BaseRepository):
return db_user_group
async def update_user_group(
self,
user_group_id: UUID,
user_group_update: schemas.UserGroupUpdate
self, user_group_id: UUID, user_group_update: schemas.UserGroupUpdate
) -> Optional[models.UserGroup]:
"""
Update a user group.
"""
update_values = user_group_update.model_dump(exclude_unset=True)
query = update(models.UserGroup).\
where(models.UserGroup.user_group_id == user_group_id).\
values(update_values)
query = update(models.UserGroup).where(models.UserGroup.user_group_id == user_group_id).values(update_values)
await self._db_session.execute(query)
await self._db_session.commit()
@@ -244,18 +235,16 @@ class UsersRepository(BaseRepository):
await self._db_session.commit()
return result.rowcount > 0
async def add_member_to_user_group(
self,
user_group_id: UUID,
user: models.User
) -> Union[None, models.UserGroup]:
async def add_member_to_user_group(self, user_group_id: UUID, user: models.User) -> Union[None, models.UserGroup]:
"""
Add a member to a user group.
"""
query = select(models.UserGroup).\
options(selectinload(models.UserGroup.users)).\
where(models.UserGroup.user_group_id == user_group_id)
query = (
select(models.UserGroup)
.options(selectinload(models.UserGroup.users))
.where(models.UserGroup.user_group_id == user_group_id)
)
result = await self._db_session.execute(query)
user_group_db = result.scalars().first()
if not user_group_db:
@@ -267,17 +256,17 @@ class UsersRepository(BaseRepository):
return user_group_db
async def remove_member_from_user_group(
self,
user_group_id: UUID,
user: models.User
self, user_group_id: UUID, user: models.User
) -> Union[None, models.UserGroup]:
"""
Remove a member from a user group.
"""
query = select(models.UserGroup).\
options(selectinload(models.UserGroup.users)).\
where(models.UserGroup.user_group_id == user_group_id)
query = (
select(models.UserGroup)
.options(selectinload(models.UserGroup.users))
.where(models.UserGroup.user_group_id == user_group_id)
)
result = await self._db_session.execute(query)
user_group_db = result.scalars().first()
if not user_group_db:
@@ -293,9 +282,7 @@ class UsersRepository(BaseRepository):
Get all members from a user group.
"""
query = select(models.User).\
join(models.User.groups).\
filter(models.UserGroup.user_group_id == user_group_id)
query = select(models.User).join(models.User.groups).filter(models.UserGroup.user_group_id == user_group_id)
result = await self._db_session.execute(query)
return result.scalars().all()