ppt-tool/backend/services/access_service.py
Vadym Samoilenko cf21ba4516 Phase 1-2: Foundation + Admin Panel & Client Management
Phase 1 (Foundation):
- Project restructure (presenton-main → backend/ + frontend/)
- Database schema (8 new models, Alembic config, seed script)
- Auth (Azure AD SSO + dev bypass, JWT sessions, AuthMiddleware)
- RBAC (access_service, rbac_middleware, admin routers)
- Audit logging (fire-and-forget, AuditMiddleware, admin router)
- i18n (react-i18next with 5 namespace files)

Phase 2 (Admin Panel & Client Management):
- Admin panel shell (sidebar layout, role guard, 12 pages)
- Redux admin slice with 18 async thunks
- User management (role changes, deactivation)
- Client management (CRUD, brand config, team management)
- Brand config editor (colors, fonts, logos, voice rules)
- Master deck upload & parser (PPTX → HTML → React pipeline)
- Audit log viewer with filters and CSV/JSON export

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:37:17 +00:00

56 lines
1.8 KiB
Python

"""Service for determining resource access based on user role and team memberships."""
import uuid
from typing import List
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from models.sql.client import ClientModel
from models.sql.team import TeamModel
from models.sql.team_membership import TeamMembershipModel
from models.sql.user import UserModel
async def get_accessible_client_ids(user: UserModel, session: AsyncSession) -> List[uuid.UUID]:
"""Return client IDs the user can access.
super_admin: all active clients.
Others: clients linked via team memberships.
"""
if user.role == "super_admin":
result = await session.execute(
select(ClientModel.id).where(ClientModel.is_active == True) # noqa: E712
)
return list(result.scalars().all())
result = await session.execute(
select(TeamModel.client_id)
.join(TeamMembershipModel, TeamMembershipModel.team_id == TeamModel.id)
.where(
TeamMembershipModel.user_id == user.id,
TeamModel.client_id.isnot(None),
)
.distinct()
)
return list(result.scalars().all())
async def get_accessible_clients(user: UserModel, session: AsyncSession) -> List[ClientModel]:
"""Return full ClientModel objects the user can access."""
if user.role == "super_admin":
result = await session.execute(
select(ClientModel).where(ClientModel.is_active == True) # noqa: E712
)
return list(result.scalars().all())
client_ids = await get_accessible_client_ids(user, session)
if not client_ids:
return []
result = await session.execute(
select(ClientModel).where(
ClientModel.id.in_(client_ids),
ClientModel.is_active == True, # noqa: E712
)
)
return list(result.scalars().all())