# app/api/v1/endpoints/invites.py import logging from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.api.dependencies import get_current_user from app.models import User as UserModel, UserRoleEnum from app.schemas.invite import InviteAccept from app.schemas.message import Message from app.crud import invite as crud_invite from app.crud import group as crud_group logger = logging.getLogger(__name__) router = APIRouter() @router.post( "/accept", # Route relative to prefix "/invites" response_model=Message, summary="Accept Group Invite", tags=["Invites"] ) async def accept_invite( invite_in: InviteAccept, db: AsyncSession = Depends(get_db), current_user: UserModel = Depends(get_current_user), ): """Allows an authenticated user to accept an invite using its code.""" code = invite_in.code logger.info(f"User {current_user.email} attempting to accept invite code: {code}") # Find the active, non-expired invite invite = await crud_invite.get_active_invite_by_code(db=db, code=code) if not invite: logger.warning(f"Invite code '{code}' not found, expired, or already used.") raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Invite code is invalid or expired") group_id = invite.group_id # Check if user is already in the group is_member = await crud_group.is_user_member(db=db, group_id=group_id, user_id=current_user.id) if is_member: logger.info(f"User {current_user.email} is already a member of group {group_id}. Invite '{code}' still deactivated.") # Deactivate invite even if already member, to prevent reuse await crud_invite.deactivate_invite(db=db, invite=invite) return Message(detail="You are already a member of this group.") # Add user to the group as a member added = await crud_group.add_user_to_group(db=db, group_id=group_id, user_id=current_user.id, role=UserRoleEnum.member) if not added: # Should not happen if is_member check was correct, but handle defensively logger.error(f"Failed to add user {current_user.email} to group {group_id} via invite '{code}' despite not being a member.") raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Could not join group.") # Deactivate the invite (single-use) await crud_invite.deactivate_invite(db=db, invite=invite) logger.info(f"User {current_user.email} successfully joined group {group_id} using invite '{code}'.") return Message(detail="Successfully joined the group.")