"""API routes for chat room management FastAPI router with all room-related endpoints """ from fastapi import APIRouter, Depends, HTTPException, status, Query from sqlalchemy.orm import Session from typing import List, Optional from app.core.database import get_db from app.modules.auth import get_current_user from app.modules.chat_room import schemas from app.modules.chat_room.models import MemberRole, RoomStatus from app.modules.chat_room.services.room_service import room_service from app.modules.chat_room.services.membership_service import membership_service from app.modules.chat_room.services.template_service import template_service from app.modules.chat_room.dependencies import ( get_current_room, require_room_permission, validate_room_owner, require_admin, get_user_effective_role ) router = APIRouter(prefix="/api/rooms", tags=["Chat Rooms"]) # Room CRUD Endpoints @router.post("", response_model=schemas.RoomResponse, status_code=status.HTTP_201_CREATED) async def create_room( room_data: schemas.CreateRoomRequest, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Create a new incident room""" user_email = current_user["username"] # Check if using template if room_data.template: template = template_service.get_template_by_name(db, room_data.template) if template: room = template_service.create_room_from_template( db, template.template_id, user_email, room_data.title, room_data.location, room_data.description ) else: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=f"Template '{room_data.template}' not found" ) else: room = room_service.create_room(db, user_email, room_data) # Get user role for response role = membership_service.get_user_role_in_room(db, room.room_id, user_email) return schemas.RoomResponse( **room.__dict__, current_user_role=role ) @router.get("", response_model=schemas.RoomListResponse) async def list_rooms( status: Optional[RoomStatus] = None, incident_type: Optional[schemas.IncidentType] = None, severity: Optional[schemas.SeverityLevel] = None, search: Optional[str] = None, all: bool = Query(False, description="Admin only: show all rooms"), limit: int = Query(20, ge=1, le=100), offset: int = Query(0, ge=0), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """List rooms accessible to current user""" user_email = current_user["username"] is_admin = membership_service.is_system_admin(user_email) # Create filter params filters = schemas.RoomFilterParams( status=status, incident_type=incident_type, severity=severity, search=search, all=all, limit=limit, offset=offset ) rooms, total = room_service.list_user_rooms(db, user_email, filters, is_admin) # Add user role to each room room_responses = [] for room in rooms: role = membership_service.get_user_role_in_room(db, room.room_id, user_email) room_response = schemas.RoomResponse( **room.__dict__, current_user_role=role, is_admin_view=is_admin and all ) room_responses.append(room_response) return schemas.RoomListResponse( rooms=room_responses, total=total, limit=limit, offset=offset ) @router.get("/{room_id}", response_model=schemas.RoomResponse) async def get_room_details( room_id: str, room = Depends(get_current_room), role: Optional[MemberRole] = Depends(get_user_effective_role), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Get room details including members""" # Load members members = membership_service.get_room_members(db, room.room_id) member_responses = [schemas.MemberResponse.from_orm(m) for m in members] is_admin = membership_service.is_system_admin(current_user["username"]) return schemas.RoomResponse( **room.__dict__, members=member_responses, current_user_role=role, is_admin_view=is_admin ) @router.patch("/{room_id}", response_model=schemas.RoomResponse) async def update_room( room_id: str, updates: schemas.UpdateRoomRequest, _: None = Depends(require_room_permission("update_metadata")), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Update room metadata""" try: room = room_service.update_room(db, room_id, updates) if not room: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Room not found" ) role = membership_service.get_user_role_in_room(db, room_id, current_user["username"]) return schemas.RoomResponse(**room.__dict__, current_user_role=role) except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e) ) @router.delete("/{room_id}", response_model=schemas.SuccessResponse) async def delete_room( room_id: str, _: None = Depends(validate_room_owner), db: Session = Depends(get_db) ): """Soft delete (archive) a room""" success = room_service.delete_room(db, room_id) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Room not found" ) return schemas.SuccessResponse(message="Room archived successfully") # Membership Endpoints @router.get("/{room_id}/members", response_model=List[schemas.MemberResponse]) async def list_room_members( room_id: str, _ = Depends(get_current_room), db: Session = Depends(get_db) ): """List all members of a room""" members = membership_service.get_room_members(db, room_id) return [schemas.MemberResponse.from_orm(m) for m in members] @router.post("/{room_id}/members", response_model=schemas.MemberResponse) async def add_member( room_id: str, request: schemas.AddMemberRequest, _: None = Depends(require_room_permission("manage_members")), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Add a member to the room""" member = membership_service.add_member( db, room_id, request.user_id, request.role, current_user["username"] ) if not member: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="User is already a member" ) # Update room activity room_service.update_room_activity(db, room_id) return schemas.MemberResponse.from_orm(member) @router.patch("/{room_id}/members/{user_id}", response_model=schemas.MemberResponse) async def update_member_role( room_id: str, user_id: str, request: schemas.UpdateMemberRoleRequest, _: None = Depends(validate_room_owner), db: Session = Depends(get_db) ): """Update a member's role""" member = membership_service.update_member_role( db, room_id, user_id, request.role ) if not member: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Member not found" ) # Update room activity room_service.update_room_activity(db, room_id) return schemas.MemberResponse.from_orm(member) @router.delete("/{room_id}/members/{user_id}", response_model=schemas.SuccessResponse) async def remove_member( room_id: str, user_id: str, _: None = Depends(require_room_permission("manage_members")), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Remove a member from the room""" # Prevent removing the last owner if user_id == current_user["username"]: role = membership_service.get_user_role_in_room(db, room_id, user_id) if role == MemberRole.OWNER: # Check if there are other owners members = membership_service.get_room_members(db, room_id) owner_count = sum(1 for m in members if m.role == MemberRole.OWNER) if owner_count == 1: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="Cannot remove the last owner" ) success = membership_service.remove_member(db, room_id, user_id) if not success: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Member not found" ) # Update room activity room_service.update_room_activity(db, room_id) return schemas.SuccessResponse(message="Member removed successfully") @router.post("/{room_id}/transfer-ownership", response_model=schemas.SuccessResponse) async def transfer_ownership( room_id: str, request: schemas.TransferOwnershipRequest, _: None = Depends(validate_room_owner), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Transfer room ownership to another member""" success = membership_service.transfer_ownership( db, room_id, current_user["username"], request.new_owner_id ) if not success: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="New owner must be an existing room member" ) return schemas.SuccessResponse(message="Ownership transferred successfully") # Permission Endpoints @router.get("/{room_id}/permissions", response_model=schemas.PermissionResponse) async def get_user_permissions( room_id: str, role: Optional[MemberRole] = Depends(get_user_effective_role), db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """Get current user's permissions in the room""" user_email = current_user["username"] is_admin = membership_service.is_system_admin(user_email) if is_admin: # Admin has all permissions return schemas.PermissionResponse( role=role or MemberRole.OWNER, is_admin=True, can_read=True, can_write=True, can_manage_members=True, can_transfer_ownership=True, can_update_status=True, can_delete=True ) if not role: # Not a member return schemas.PermissionResponse( role=None, is_admin=False, can_read=False, can_write=False, can_manage_members=False, can_transfer_ownership=False, can_update_status=False, can_delete=False ) # Return permissions based on role permissions = { MemberRole.OWNER: schemas.PermissionResponse( role=role, is_admin=False, can_read=True, can_write=True, can_manage_members=True, can_transfer_ownership=True, can_update_status=True, can_delete=True ), MemberRole.EDITOR: schemas.PermissionResponse( role=role, is_admin=False, can_read=True, can_write=True, can_manage_members=False, can_transfer_ownership=False, can_update_status=False, can_delete=False ), MemberRole.VIEWER: schemas.PermissionResponse( role=role, is_admin=False, can_read=True, can_write=False, can_manage_members=False, can_transfer_ownership=False, can_update_status=False, can_delete=False ) } return permissions[role] # Template Endpoints @router.get("/templates", response_model=List[schemas.TemplateResponse]) async def list_templates( db: Session = Depends(get_db), _: dict = Depends(get_current_user) ): """List available room templates""" templates = template_service.get_templates(db) return [schemas.TemplateResponse.from_orm(t) for t in templates]