Spaces:
Sleeping
Sleeping
| """ | |
| Channel Routes - REST API for channel management. | |
| OpenClaw Integration: Context-specific conversations (project, support, engineering, general). | |
| """ | |
| from fastapi import APIRouter, Depends, HTTPException, Query | |
| from pydantic import BaseModel | |
| from sqlalchemy.orm import Session | |
| from typing import List, Optional | |
| from core.models import Channel, get_db | |
| router = APIRouter(prefix="/api/channels", tags=["Channels"]) | |
| class CreateChannelRequest(BaseModel): | |
| name: str # project-xyz, support, engineering | |
| display_name: str # "Project XYZ", "Support", "Engineering" | |
| description: Optional[str] = None | |
| channel_type: str # project, support, engineering, general | |
| is_public: bool = True | |
| created_by: str # user_id | |
| agent_members: List[str] = [] | |
| user_members: List[str] = [] | |
| class UpdateChannelRequest(BaseModel): | |
| display_name: Optional[str] = None | |
| description: Optional[str] = None | |
| is_public: Optional[bool] = None | |
| agent_members: Optional[List[str]] = None | |
| user_members: Optional[List[str]] = None | |
| class ChannelResponse(BaseModel): | |
| id: str | |
| name: str | |
| display_name: str | |
| description: Optional[str] | |
| channel_type: str | |
| is_public: bool | |
| created_by: str | |
| agent_members: List[str] | |
| user_members: List[str] | |
| created_at: str | |
| async def create_channel( | |
| request: CreateChannelRequest, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Create new channel. | |
| **Channel Types:** | |
| - project: Project-specific discussions | |
| - support: Customer support coordination | |
| - engineering: Technical discussions | |
| - general: Default public channel | |
| **Access Control:** | |
| - Humans can create channels | |
| - is_public=false for private channels | |
| - agent_members and user_members control access | |
| """ | |
| # Check if channel name already exists | |
| existing = db.query(Channel).filter(Channel.name == request.name).first() | |
| if existing: | |
| raise HTTPException(status_code=400, detail=f"Channel {request.name} already exists") | |
| # Validate channel_type | |
| valid_types = ["project", "support", "engineering", "general"] | |
| if request.channel_type not in valid_types: | |
| raise HTTPException( | |
| status_code=400, | |
| detail=f"Invalid channel_type '{request.channel_type}'. Must be one of: {', '.join(valid_types)}" | |
| ) | |
| channel = Channel( | |
| name=request.name, | |
| display_name=request.display_name, | |
| description=request.description, | |
| channel_type=request.channel_type, | |
| is_public=request.is_public, | |
| created_by=request.created_by, | |
| agent_members=request.agent_members, | |
| user_members=request.user_members | |
| ) | |
| db.add(channel) | |
| db.commit() | |
| db.refresh(channel) | |
| return ChannelResponse( | |
| id=channel.id, | |
| name=channel.name, | |
| display_name=channel.display_name, | |
| description=channel.description, | |
| channel_type=channel.channel_type, | |
| is_public=channel.is_public, | |
| created_by=channel.created_by, | |
| agent_members=channel.agent_members, | |
| user_members=channel.user_members, | |
| created_at=channel.created_at.isoformat() | |
| ) | |
| async def list_channels( | |
| channel_type: Optional[str] = None, | |
| is_public: Optional[bool] = None, | |
| limit: int = Query(50, le=100), | |
| offset: int = Query(0, ge=0), | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| List all channels. | |
| **Filters:** | |
| - channel_type: Filter by type (project, support, engineering, general) | |
| - is_public: Filter by public/private | |
| - Pagination: limit + offset | |
| """ | |
| query = db.query(Channel) | |
| if channel_type: | |
| query = query.filter(Channel.channel_type == channel_type) | |
| if is_public is not None: | |
| query = query.filter(Channel.is_public == is_public) | |
| channels = query.order_by(Channel.created_at.desc()).offset(offset).limit(limit).all() | |
| return [ | |
| ChannelResponse( | |
| id=c.id, | |
| name=c.name, | |
| display_name=c.display_name, | |
| description=c.description, | |
| channel_type=c.channel_type, | |
| is_public=c.is_public, | |
| created_by=c.created_by, | |
| agent_members=c.agent_members, | |
| user_members=c.user_members, | |
| created_at=c.created_at.isoformat() | |
| ) | |
| for c in channels | |
| ] | |
| async def get_channel( | |
| channel_id: str, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Get channel by ID. | |
| """ | |
| channel = db.query(Channel).filter(Channel.id == channel_id).first() | |
| if not channel: | |
| raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found") | |
| return ChannelResponse( | |
| id=channel.id, | |
| name=channel.name, | |
| display_name=channel.display_name, | |
| description=channel.description, | |
| channel_type=channel.channel_type, | |
| is_public=channel.is_public, | |
| created_by=channel.created_by, | |
| agent_members=channel.agent_members, | |
| user_members=channel.user_members, | |
| created_at=channel.created_at.isoformat() | |
| ) | |
| async def update_channel( | |
| channel_id: str, | |
| request: UpdateChannelRequest, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Update channel. | |
| Only update fields that are provided. | |
| """ | |
| channel = db.query(Channel).filter(Channel.id == channel_id).first() | |
| if not channel: | |
| raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found") | |
| if request.display_name is not None: | |
| channel.display_name = request.display_name | |
| if request.description is not None: | |
| channel.description = request.description | |
| if request.is_public is not None: | |
| channel.is_public = request.is_public | |
| if request.agent_members is not None: | |
| channel.agent_members = request.agent_members | |
| if request.user_members is not None: | |
| channel.user_members = request.user_members | |
| db.commit() | |
| db.refresh(channel) | |
| return ChannelResponse( | |
| id=channel.id, | |
| name=channel.name, | |
| display_name=channel.display_name, | |
| description=channel.description, | |
| channel_type=channel.channel_type, | |
| is_public=channel.is_public, | |
| created_by=channel.created_by, | |
| agent_members=channel.agent_members, | |
| user_members=channel.user_members, | |
| created_at=channel.created_at.isoformat() | |
| ) | |
| async def delete_channel( | |
| channel_id: str, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Delete channel. | |
| **Warning:** This will also delete all posts in this channel. | |
| """ | |
| channel = db.query(Channel).filter(Channel.id == channel_id).first() | |
| if not channel: | |
| raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found") | |
| db.delete(channel) | |
| db.commit() | |
| return {"message": f"Channel {channel_id} deleted"} | |
| async def add_channel_member( | |
| channel_id: str, | |
| member_type: str, # "agent" or "user" | |
| member_id: str, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Add member to channel. | |
| ** member_type: "agent" or "user" | |
| ** member_id: agent_id or user_id | |
| """ | |
| channel = db.query(Channel).filter(Channel.id == channel_id).first() | |
| if not channel: | |
| raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found") | |
| if member_type == "agent": | |
| if member_id not in channel.agent_members: | |
| channel.agent_members.append(member_id) | |
| elif member_type == "user": | |
| if member_id not in channel.user_members: | |
| channel.user_members.append(member_id) | |
| else: | |
| raise HTTPException(status_code=400, detail=f"Invalid member_type '{member_type}'. Must be 'agent' or 'user'") | |
| db.commit() | |
| db.refresh(channel) | |
| return { | |
| "message": f"Added {member_type} {member_id} to channel {channel_id}", | |
| "agent_members": channel.agent_members, | |
| "user_members": channel.user_members | |
| } | |
| async def remove_channel_member( | |
| channel_id: str, | |
| member_type: str, # "agent" or "user" | |
| member_id: str, | |
| db: Session = Depends(get_db) | |
| ): | |
| """ | |
| Remove member from channel. | |
| ** member_type: "agent" or "user" | |
| ** member_id: agent_id or user_id | |
| """ | |
| channel = db.query(Channel).filter(Channel.id == channel_id).first() | |
| if not channel: | |
| raise HTTPException(status_code=404, detail=f"Channel {channel_id} not found") | |
| if member_type == "agent": | |
| if member_id in channel.agent_members: | |
| channel.agent_members.remove(member_id) | |
| elif member_type == "user": | |
| if member_id in channel.user_members: | |
| channel.user_members.remove(member_id) | |
| else: | |
| raise HTTPException(status_code=400, detail=f"Invalid member_type '{member_type}'. Must be 'agent' or 'user'") | |
| db.commit() | |
| db.refresh(channel) | |
| return { | |
| "message": f"Removed {member_type} {member_id} from channel {channel_id}", | |
| "agent_members": channel.agent_members, | |
| "user_members": channel.user_members | |
| } | |