Initial commit: Rentman Clone - Phase 0-6 (T001-T023)

Completed:
- Phase 0: Project Setup (T001-T003) - Docker Compose, FastAPI skeleton, React SPA
- Phase 1: Auth System (T004-T008) - DB models, JWT auth, RBAC middleware, user management
- Phase 2: Contacts & Tags (T009-T011) - CRUD API + UI
- Phase 3: Equipment Catalog (T012-T014) - Models, API, UI with barcode/QR
- Phase 4: Crew Management (T015-T017) - Models, availability, UI
- Phase 5: Vehicle Fleet (T018-T020) - Models, assignments, UI
- Phase 6: Projects (T021-T023) - Project hierarchy models, CRUD API, list/detail UI
This commit is contained in:
Agent Zero
2026-05-31 20:36:42 +00:00
commit 7f7da15965
135 changed files with 18980 additions and 0 deletions
+88
View File
@@ -0,0 +1,88 @@
"""Role management endpoints (admin)."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_current_user, require_permission
from app.db.session import get_async_session
from app.models import User, Role
from app.schemas.role import RoleCreateRequest, RoleUpdateRequest, RoleResponse
router = APIRouter(prefix="/roles", tags=["roles"])
@router.get("", response_model=list[RoleResponse])
async def list_roles(
current_user: User = Depends(require_permission("roles:read")),
session: AsyncSession = Depends(get_async_session),
):
"""List all roles within the current account."""
account_id = current_user.account_id
result = await session.execute(
select(Role).where(Role.account_id == account_id).order_by(Role.name)
)
roles = result.scalars().all()
return [RoleResponse.model_validate(r) for r in roles]
@router.post("", response_model=RoleResponse, status_code=status.HTTP_201_CREATED)
async def create_role(
body: RoleCreateRequest,
current_user: User = Depends(require_permission("roles:write")),
session: AsyncSession = Depends(get_async_session),
):
"""Create a new role within the current account."""
account_id = current_user.account_id
# Check name uniqueness within account
existing = await session.execute(
select(Role).where(Role.account_id == account_id, Role.name == body.name)
)
if existing.scalars().first():
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="A role with this name already exists in your account",
)
role = Role(
account_id=account_id,
name=body.name,
description=body.description,
permissions=body.permissions,
)
session.add(role)
await session.commit()
await session.refresh(role)
return RoleResponse.model_validate(role)
@router.put("/{role_id}", response_model=RoleResponse)
async def update_role(
role_id: str,
body: RoleUpdateRequest,
current_user: User = Depends(require_permission("roles:write")),
session: AsyncSession = Depends(get_async_session),
):
"""Update a role's permissions, name, or description."""
account_id = current_user.account_id
result = await session.execute(
select(Role).where(Role.id == role_id, Role.account_id == account_id)
)
role = result.scalars().first()
if not role:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Role not found",
)
if body.name is not None:
role.name = body.name
if body.description is not None:
role.description = body.description
if body.permissions is not None:
role.permissions = body.permissions
await session.commit()
await session.refresh(role)
return RoleResponse.model_validate(role)