""" Session API router for ClaudeTools. This module defines all REST API endpoints for managing sessions, including CRUD operations with proper authentication, validation, and error handling. """ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.orm import Session from api.database import get_db from api.middleware.auth import get_current_user from api.schemas.session import ( SessionCreate, SessionResponse, SessionUpdate, ) from api.services import session_service # Create router with prefix and tags router = APIRouter() @router.get( "", response_model=dict, summary="List all sessions", description="Retrieve a paginated list of all sessions with optional filtering", status_code=status.HTTP_200_OK, ) def list_sessions( skip: int = Query( default=0, ge=0, description="Number of records to skip for pagination" ), limit: int = Query( default=100, ge=1, le=1000, description="Maximum number of records to return (max 1000)" ), project_id: UUID | None = Query( default=None, description="Filter sessions by project ID" ), machine_id: UUID | None = Query( default=None, description="Filter sessions by machine ID" ), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ List all sessions with pagination. - **skip**: Number of sessions to skip (default: 0) - **limit**: Maximum number of sessions to return (default: 100, max: 1000) - **project_id**: Optional filter by project ID - **machine_id**: Optional filter by machine ID Returns a list of sessions with pagination metadata. **Example Request:** ``` GET /api/sessions?skip=0&limit=50 Authorization: Bearer ``` **Example Response:** ```json { "total": 15, "skip": 0, "limit": 50, "sessions": [ { "id": "123e4567-e89b-12d3-a456-426614174000", "session_title": "Database migration work", "session_date": "2024-01-15", "status": "completed", "duration_minutes": 120, "is_billable": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ] } ``` """ try: # Filter by project if specified if project_id: sessions, total = session_service.get_sessions_by_project(db, project_id, skip, limit) # Filter by machine if specified elif machine_id: sessions, total = session_service.get_sessions_by_machine(db, machine_id, skip, limit) # Otherwise get all sessions else: sessions, total = session_service.get_sessions(db, skip, limit) return { "total": total, "skip": skip, "limit": limit, "sessions": [SessionResponse.model_validate(session) for session in sessions] } except Exception as e: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to retrieve sessions: {str(e)}" ) @router.get( "/{session_id}", response_model=SessionResponse, summary="Get session by ID", description="Retrieve a single session by its unique identifier", status_code=status.HTTP_200_OK, responses={ 200: { "description": "Session found and returned", "model": SessionResponse, }, 404: { "description": "Session not found", "content": { "application/json": { "example": {"detail": "Session with ID 123e4567-e89b-12d3-a456-426614174000 not found"} } }, }, }, ) def get_session( session_id: UUID, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Get a specific session by ID. - **session_id**: UUID of the session to retrieve Returns the complete session details. **Example Request:** ``` GET /api/sessions/123e4567-e89b-12d3-a456-426614174000 Authorization: Bearer ``` **Example Response:** ```json { "id": "123e4567-e89b-12d3-a456-426614174000", "client_id": "456e7890-e89b-12d3-a456-426614174001", "project_id": "789e0123-e89b-12d3-a456-426614174002", "machine_id": "012e3456-e89b-12d3-a456-426614174003", "session_date": "2024-01-15", "start_time": "2024-01-15T09:00:00Z", "end_time": "2024-01-15T11:00:00Z", "duration_minutes": 120, "status": "completed", "session_title": "Database migration work", "summary": "Migrated customer database to new schema version", "is_billable": true, "billable_hours": 2.0, "technician": "John Doe", "session_log_file": "/logs/2024-01-15-db-migration.md", "notes": "Successful migration with no issues", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ``` """ session = session_service.get_session_by_id(db, session_id) return SessionResponse.model_validate(session) @router.post( "", response_model=SessionResponse, summary="Create new session", description="Create a new session with the provided details", status_code=status.HTTP_201_CREATED, responses={ 201: { "description": "Session created successfully", "model": SessionResponse, }, 404: { "description": "Referenced project or machine not found", "content": { "application/json": { "example": {"detail": "Project with ID 123e4567-e89b-12d3-a456-426614174000 not found"} } }, }, 422: { "description": "Validation error", "content": { "application/json": { "example": { "detail": [ { "loc": ["body", "session_title"], "msg": "field required", "type": "value_error.missing" } ] } } }, }, }, ) def create_session( session_data: SessionCreate, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Create a new session. Requires a valid JWT token with appropriate permissions. **Example Request:** ```json POST /api/sessions Authorization: Bearer Content-Type: application/json { "session_title": "Database migration work", "session_date": "2024-01-15", "project_id": "789e0123-e89b-12d3-a456-426614174002", "machine_id": "012e3456-e89b-12d3-a456-426614174003", "start_time": "2024-01-15T09:00:00Z", "end_time": "2024-01-15T11:00:00Z", "duration_minutes": 120, "status": "completed", "summary": "Migrated customer database to new schema version", "is_billable": true, "billable_hours": 2.0, "technician": "John Doe" } ``` **Example Response:** ```json { "id": "123e4567-e89b-12d3-a456-426614174000", "session_title": "Database migration work", "session_date": "2024-01-15", "status": "completed", "duration_minutes": 120, "is_billable": true, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ``` """ session = session_service.create_session(db, session_data) return SessionResponse.model_validate(session) @router.put( "/{session_id}", response_model=SessionResponse, summary="Update session", description="Update an existing session's details", status_code=status.HTTP_200_OK, responses={ 200: { "description": "Session updated successfully", "model": SessionResponse, }, 404: { "description": "Session, project, or machine not found", "content": { "application/json": { "example": {"detail": "Session with ID 123e4567-e89b-12d3-a456-426614174000 not found"} } }, }, 422: { "description": "Validation error", "content": { "application/json": { "example": {"detail": "Invalid project_id"} } }, }, }, ) def update_session( session_id: UUID, session_data: SessionUpdate, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Update an existing session. - **session_id**: UUID of the session to update Only provided fields will be updated. All fields are optional. **Example Request:** ```json PUT /api/sessions/123e4567-e89b-12d3-a456-426614174000 Authorization: Bearer Content-Type: application/json { "status": "completed", "end_time": "2024-01-15T11:00:00Z", "duration_minutes": 120, "summary": "Successfully completed database migration" } ``` **Example Response:** ```json { "id": "123e4567-e89b-12d3-a456-426614174000", "session_title": "Database migration work", "session_date": "2024-01-15", "status": "completed", "duration_minutes": 120, "summary": "Successfully completed database migration", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T14:20:00Z" } ``` """ session = session_service.update_session(db, session_id, session_data) return SessionResponse.model_validate(session) @router.delete( "/{session_id}", response_model=dict, summary="Delete session", description="Delete a session by its ID", status_code=status.HTTP_200_OK, responses={ 200: { "description": "Session deleted successfully", "content": { "application/json": { "example": { "message": "Session deleted successfully", "session_id": "123e4567-e89b-12d3-a456-426614174000" } } }, }, 404: { "description": "Session not found", "content": { "application/json": { "example": {"detail": "Session with ID 123e4567-e89b-12d3-a456-426614174000 not found"} } }, }, }, ) def delete_session( session_id: UUID, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user), ): """ Delete a session. - **session_id**: UUID of the session to delete This is a permanent operation and cannot be undone. **Example Request:** ``` DELETE /api/sessions/123e4567-e89b-12d3-a456-426614174000 Authorization: Bearer ``` **Example Response:** ```json { "message": "Session deleted successfully", "session_id": "123e4567-e89b-12d3-a456-426614174000" } ``` """ return session_service.delete_session(db, session_id)