|
| 1 | +import logging |
| 2 | +from abc import ABC, abstractmethod |
| 3 | +from typing import Generic, TypeVar, final |
| 4 | + |
| 5 | +import sqlalchemy as sa |
| 6 | +from sqlalchemy.exc import IntegrityError |
| 7 | +from sqlalchemy.ext.asyncio import AsyncSession as SASession |
| 8 | + |
| 9 | +from ai.backend.logging import BraceStyleAdapter |
| 10 | +from ai.backend.manager.data.permission.association_scopes_entities import ( |
| 11 | + AssociationScopesEntitiesCreateInput, |
| 12 | +) |
| 13 | +from ai.backend.manager.data.permission.id import ObjectId, ScopeId |
| 14 | +from ai.backend.manager.models.rbac_models.association_scopes_entities import ( |
| 15 | + AssociationScopesEntitiesRow, |
| 16 | +) |
| 17 | + |
| 18 | +log = BraceStyleAdapter(logging.getLogger(__name__)) |
| 19 | + |
| 20 | + |
| 21 | +class RBACEntityDeletor(ABC): |
| 22 | + async def delete_entity(self, db_session: SASession) -> None: |
| 23 | + scope_id = self.scope_id() |
| 24 | + entity_id = self.object_id() |
| 25 | + try: |
| 26 | + await db_session.execute( |
| 27 | + sa.delete(AssociationScopesEntitiesRow).where( |
| 28 | + sa.and_( |
| 29 | + AssociationScopesEntitiesRow.scope_id == scope_id.scope_id, |
| 30 | + AssociationScopesEntitiesRow.scope_type == scope_id.scope_type, |
| 31 | + AssociationScopesEntitiesRow.entity_id == entity_id, |
| 32 | + AssociationScopesEntitiesRow.entity_type == entity_id.entity_type, |
| 33 | + ) |
| 34 | + ) |
| 35 | + ) |
| 36 | + except IntegrityError: |
| 37 | + log.exception( |
| 38 | + "failed to delete entity and scope mapping: {}, {}.", |
| 39 | + entity_id.to_str(), |
| 40 | + scope_id.to_str(), |
| 41 | + ) |
| 42 | + |
| 43 | + @abstractmethod |
| 44 | + def scope_id(self) -> ScopeId: |
| 45 | + raise NotImplementedError |
| 46 | + |
| 47 | + @abstractmethod |
| 48 | + def object_id(self) -> ObjectId: |
| 49 | + raise NotImplementedError |
| 50 | + |
| 51 | + |
| 52 | +TDeletedEntity = TypeVar("TDeletedEntity") |
| 53 | + |
| 54 | + |
| 55 | +class RBACDeletor(Generic[TDeletedEntity], ABC): |
| 56 | + def __init__(self, rbac_entity_deletor: RBACEntityDeletor) -> None: |
| 57 | + self._rbac_entity_deletor = rbac_entity_deletor |
| 58 | + |
| 59 | + @final |
| 60 | + async def delete(self, db_session: SASession) -> TDeletedEntity: |
| 61 | + entity = await self._delete(db_session) |
| 62 | + await self._rbac_entity_deletor.delete_entity(db_session) |
| 63 | + return entity |
| 64 | + |
| 65 | + @abstractmethod |
| 66 | + async def _delete(self, db_session: SASession) -> TDeletedEntity: |
| 67 | + raise NotImplementedError |
0 commit comments