cosmo/backend/app/api/social.py

109 lines
4.5 KiB
Python

"""
Social Features API routes - user follows and channel messages
"""
import logging
from typing import List
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models.db.user import User
from app.models.schemas.social import UserFollowResponse, ChannelMessageCreate, ChannelMessageResponse
from app.services.social_service import social_service
from app.api.deps import get_current_active_user
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/social", tags=["social"])
# --- User Follows ---
@router.post("/follow/{body_id}", response_model=UserFollowResponse)
async def follow_body(
body_id: str,
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Allow current user to follow a celestial body.
User will then receive events and can post in the body's channel.
"""
try:
follow = await social_service.follow_body(current_user.id, body_id, db)
return follow
except ValueError as e:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
except Exception as e:
logger.error(f"Error following body {body_id} by user {current_user.id}: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to follow body")
@router.delete("/follow/{body_id}", status_code=status.HTTP_204_NO_CONTENT)
async def unfollow_body(
body_id: str,
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""Allow current user to unfollow a celestial body."""
try:
unfollowed = await social_service.unfollow_body(current_user.id, body_id, db)
if not unfollowed:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Not following this body")
return None
except Exception as e:
logger.error(f"Error unfollowing body {body_id} by user {current_user.id}: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to unfollow body")
@router.get("/follows", response_model=List[UserFollowResponse])
async def get_user_follows(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""Get all celestial bodies currently followed by the user."""
follows = await social_service.get_user_follows_with_time(current_user.id, db)
return follows
@router.get("/follows/check/{body_id}")
async def check_if_following(
body_id: str,
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""Check if the current user is following a specific celestial body."""
is_following = await social_service.get_follow(current_user.id, body_id, db)
return {"is_following": is_following is not None}
# --- Channel Messages ---
@router.post("/channel/{body_id}/message", response_model=ChannelMessageResponse)
async def post_channel_message(
body_id: str,
message: ChannelMessageCreate,
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""
Post a message to a specific celestial body's channel.
Only users following the body can post.
"""
try:
channel_message = await social_service.post_channel_message(current_user.id, body_id, message.content, db)
return channel_message
except ValueError as e:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e)) # 403 Forbidden for not following
except Exception as e:
logger.error(f"Error posting message to channel {body_id} by user {current_user.id}: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to post message")
@router.get("/channel/{body_id}/messages", response_model=List[ChannelMessageResponse])
async def get_channel_messages(
body_id: str,
limit: int = Query(50, ge=1, le=500),
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db)
):
"""Get recent messages from a celestial body's channel."""
try:
messages = await social_service.get_channel_messages(body_id, db, limit)
return messages
except Exception as e:
logger.error(f"Error retrieving messages from channel {body_id}: {e}")
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to retrieve messages")