109 lines
4.5 KiB
Python
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") |