2025-07-01 12:54:48 +00:00

414 lines
11 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from sqlalchemy import or_, and_, func
from typing import List
from app.db.base import get_db
from app.models.user import User, Connection
from app.models.message import (
Conversation,
Message,
GroupChat,
GroupChatMember,
GroupMessage,
)
from app.schemas.message import (
MessageCreate,
MessageResponse,
ConversationResponse,
GroupChatCreate,
GroupChatResponse,
GroupMessageCreate,
GroupMessageResponse,
)
from app.api.auth import get_current_user
router = APIRouter()
# Direct Messages
@router.get("/conversations", response_model=List[ConversationResponse])
def get_conversations(
db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
"""Get user's conversations"""
conversations = (
db.query(Conversation)
.filter(
or_(
Conversation.participant_1_id == current_user.id,
Conversation.participant_2_id == current_user.id,
)
)
.order_by(Conversation.updated_at.desc())
.all()
)
result = []
for conv in conversations:
# Determine other participant
other_participant = (
conv.participant_2
if conv.participant_1_id == current_user.id
else conv.participant_1
)
# Get last message
last_message = (
db.query(Message)
.filter(Message.conversation_id == conv.id)
.order_by(Message.created_at.desc())
.first()
)
# Get unread count
unread_count = (
db.query(Message)
.filter(
Message.conversation_id == conv.id,
Message.receiver_id == current_user.id,
Message.is_read is False,
)
.count()
)
conv_response = ConversationResponse(
id=conv.id,
participant_1_id=conv.participant_1_id,
participant_2_id=conv.participant_2_id,
created_at=conv.created_at,
updated_at=conv.updated_at,
other_participant_name=f"{other_participant.first_name} {other_participant.last_name}",
other_participant_id=other_participant.id,
last_message=last_message.content if last_message else None,
unread_count=unread_count,
)
result.append(conv_response)
return result
@router.get("/conversations/{user_id}/messages", response_model=List[MessageResponse])
def get_conversation_messages(
user_id: int,
skip: int = 0,
limit: int = 50,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get messages in a conversation with specific user"""
# Check if users are connected
connection = (
db.query(Connection)
.filter(
or_(
and_(
Connection.sender_id == current_user.id,
Connection.receiver_id == user_id,
),
and_(
Connection.sender_id == user_id,
Connection.receiver_id == current_user.id,
),
),
Connection.status == "accepted",
)
.first()
)
if not connection:
raise HTTPException(status_code=403, detail="Can only message connections")
# Get or create conversation
conversation = (
db.query(Conversation)
.filter(
or_(
and_(
Conversation.participant_1_id == current_user.id,
Conversation.participant_2_id == user_id,
),
and_(
Conversation.participant_1_id == user_id,
Conversation.participant_2_id == current_user.id,
),
)
)
.first()
)
if not conversation:
conversation = Conversation(
participant_1_id=min(current_user.id, user_id),
participant_2_id=max(current_user.id, user_id),
)
db.add(conversation)
db.commit()
db.refresh(conversation)
# Get messages
messages = (
db.query(Message)
.filter(Message.conversation_id == conversation.id)
.order_by(Message.created_at.desc())
.offset(skip)
.limit(limit)
.all()
)
# Mark messages as read
db.query(Message).filter(
Message.conversation_id == conversation.id,
Message.receiver_id == current_user.id,
Message.is_read is False,
).update({"is_read": True, "read_at": func.now()})
db.commit()
# Add sender names
for message in messages:
message.sender_name = f"{message.sender.first_name} {message.sender.last_name}"
return messages
@router.post("/send", response_model=MessageResponse)
def send_message(
message: MessageCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Send a direct message"""
# Check if users are connected
connection = (
db.query(Connection)
.filter(
or_(
and_(
Connection.sender_id == current_user.id,
Connection.receiver_id == message.receiver_id,
),
and_(
Connection.sender_id == message.receiver_id,
Connection.receiver_id == current_user.id,
),
),
Connection.status == "accepted",
)
.first()
)
if not connection:
raise HTTPException(status_code=403, detail="Can only message connections")
# Get or create conversation
conversation = (
db.query(Conversation)
.filter(
or_(
and_(
Conversation.participant_1_id == current_user.id,
Conversation.participant_2_id == message.receiver_id,
),
and_(
Conversation.participant_1_id == message.receiver_id,
Conversation.participant_2_id == current_user.id,
),
)
)
.first()
)
if not conversation:
conversation = Conversation(
participant_1_id=min(current_user.id, message.receiver_id),
participant_2_id=max(current_user.id, message.receiver_id),
)
db.add(conversation)
db.commit()
db.refresh(conversation)
# Create message
db_message = Message(
conversation_id=conversation.id,
sender_id=current_user.id,
receiver_id=message.receiver_id,
content=message.content,
message_type=message.message_type,
file_url=message.file_url,
)
db.add(db_message)
# Update conversation timestamp
conversation.updated_at = func.now()
db.commit()
db.refresh(db_message)
db_message.sender_name = f"{current_user.first_name} {current_user.last_name}"
return db_message
# Group Chats
@router.post("/groups", response_model=GroupChatResponse)
def create_group_chat(
group_data: GroupChatCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a group chat"""
# Create group chat
group_chat = GroupChat(
name=group_data.name,
description=group_data.description,
created_by=current_user.id,
)
db.add(group_chat)
db.commit()
db.refresh(group_chat)
# Add creator as admin member
creator_member = GroupChatMember(
group_chat_id=group_chat.id, user_id=current_user.id, is_admin=True
)
db.add(creator_member)
# Add other members
for member_id in group_data.member_ids:
if member_id != current_user.id: # Don't add creator twice
member = GroupChatMember(group_chat_id=group_chat.id, user_id=member_id)
db.add(member)
db.commit()
group_chat.creator_name = f"{current_user.first_name} {current_user.last_name}"
group_chat.member_count = len(group_data.member_ids) + 1 # Include creator
return group_chat
@router.get("/groups", response_model=List[GroupChatResponse])
def get_my_group_chats(
db: Session = Depends(get_db), current_user: User = Depends(get_current_user)
):
"""Get user's group chats"""
# Get groups where user is a member
memberships = (
db.query(GroupChatMember)
.filter(GroupChatMember.user_id == current_user.id)
.all()
)
groups = []
for membership in memberships:
group = membership.group_chat
if group.is_active:
# Get member count
member_count = (
db.query(GroupChatMember)
.filter(GroupChatMember.group_chat_id == group.id)
.count()
)
# Get last message
last_message = (
db.query(GroupMessage)
.filter(GroupMessage.group_chat_id == group.id)
.order_by(GroupMessage.created_at.desc())
.first()
)
group.creator_name = f"{group.creator.first_name} {group.creator.last_name}"
group.member_count = member_count
group.last_message = last_message.content if last_message else None
groups.append(group)
return groups
@router.get("/groups/{group_id}/messages", response_model=List[GroupMessageResponse])
def get_group_messages(
group_id: int,
skip: int = 0,
limit: int = 50,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get group chat messages"""
# Check if user is a member
membership = (
db.query(GroupChatMember)
.filter(
GroupChatMember.group_chat_id == group_id,
GroupChatMember.user_id == current_user.id,
)
.first()
)
if not membership:
raise HTTPException(status_code=403, detail="Not a member of this group")
# Get messages
messages = (
db.query(GroupMessage)
.filter(GroupMessage.group_chat_id == group_id)
.order_by(GroupMessage.created_at.desc())
.offset(skip)
.limit(limit)
.all()
)
# Add sender names
for message in messages:
message.sender_name = f"{message.sender.first_name} {message.sender.last_name}"
return messages
@router.post("/groups/{group_id}/send", response_model=GroupMessageResponse)
def send_group_message(
group_id: int,
message: GroupMessageCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Send a group message"""
# Check if user is a member
membership = (
db.query(GroupChatMember)
.filter(
GroupChatMember.group_chat_id == group_id,
GroupChatMember.user_id == current_user.id,
)
.first()
)
if not membership:
raise HTTPException(status_code=403, detail="Not a member of this group")
# Create message
db_message = GroupMessage(
group_chat_id=group_id,
sender_id=current_user.id,
content=message.content,
message_type=message.message_type,
file_url=message.file_url,
)
db.add(db_message)
db.commit()
db.refresh(db_message)
db_message.sender_name = f"{current_user.first_name} {current_user.last_name}"
return db_message