diff --git a/surfsense_backend/app/routes/__init__.py b/surfsense_backend/app/routes/__init__.py index 4b6df350a..313367dce 100644 --- a/surfsense_backend/app/routes/__init__.py +++ b/surfsense_backend/app/routes/__init__.py @@ -5,6 +5,7 @@ from .airtable_add_connector_route import ( ) from .circleback_webhook_route import router as circleback_webhook_router from .clickup_add_connector_route import router as clickup_add_connector_router +from .comments_routes import router as comments_router from .confluence_add_connector_route import router as confluence_add_connector_router from .discord_add_connector_route import router as discord_add_connector_router from .documents_routes import router as documents_router @@ -42,6 +43,7 @@ router.include_router(editor_router) router.include_router(documents_router) router.include_router(notes_router) router.include_router(new_chat_router) # Chat with assistant-ui persistence +router.include_router(comments_router) router.include_router(podcasts_router) # Podcast task status and audio router.include_router(search_source_connectors_router) router.include_router(google_calendar_add_connector_router) diff --git a/surfsense_backend/app/routes/comments_routes.py b/surfsense_backend/app/routes/comments_routes.py new file mode 100644 index 000000000..df7ad2907 --- /dev/null +++ b/surfsense_backend/app/routes/comments_routes.py @@ -0,0 +1,78 @@ +""" +Routes for chat comments and mentions. +""" + +from fastapi import APIRouter, Depends +from sqlalchemy.ext.asyncio import AsyncSession + +from app.db import User, get_async_session +from app.schemas.comments import ( + CommentCreateRequest, + CommentListResponse, + CommentReplyResponse, + CommentResponse, + CommentUpdateRequest, +) +from app.services.comments_service import ( + create_comment, + create_reply, + delete_comment, + get_comments_for_message, + update_comment, +) +from app.users import current_active_user + +router = APIRouter() + + +@router.get("/messages/{message_id}/comments", response_model=CommentListResponse) +async def list_comments( + message_id: int, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +): + """List all comments for a message with their replies.""" + return await get_comments_for_message(session, message_id, user) + + +@router.post("/messages/{message_id}/comments", response_model=CommentResponse) +async def add_comment( + message_id: int, + request: CommentCreateRequest, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +): + """Create a top-level comment on an AI response.""" + return await create_comment(session, message_id, request.content, user) + + +@router.post("/comments/{comment_id}/replies", response_model=CommentReplyResponse) +async def add_reply( + comment_id: int, + request: CommentCreateRequest, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +): + """Reply to an existing comment.""" + return await create_reply(session, comment_id, request.content, user) + + +@router.put("/comments/{comment_id}", response_model=CommentReplyResponse) +async def edit_comment( + comment_id: int, + request: CommentUpdateRequest, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +): + """Update a comment's content (author only).""" + return await update_comment(session, comment_id, request.content, user) + + +@router.delete("/comments/{comment_id}") +async def remove_comment( + comment_id: int, + session: AsyncSession = Depends(get_async_session), + user: User = Depends(current_active_user), +): + """Delete a comment (author or user with COMMENTS_DELETE permission).""" + return await delete_comment(session, comment_id, user)