""" 好友路由。 按“用户向博主申请、博主审批”实现(Friend.user_id 为申请人): - POST /api/friend/apply 申请好友(登录用户;博主与已是好友的用户不可申请) - GET /api/friend/status 查询当前用户的好友状态(none / pending / accepted / rejected) - GET /api/friend/applications 好友申请列表(仅博主) - POST /api/friend/{friend_id}/approve 审批通过(仅博主):申请人角色提升为 friend - POST /api/friend/{friend_id}/reject 审批拒绝(仅博主) """ from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from ..auth import get_current_user from ..database import get_db from ..models import ( FRIEND_STATUS_ACCEPTED, FRIEND_STATUS_PENDING, FRIEND_STATUS_REJECTED, ROLE_BLOGGER, ROLE_FRIEND, Friend, User, ) from ..schemas import UnifiedResponse router = APIRouter(prefix="/api/friend", tags=["friend"]) @router.post("/apply", response_model=UnifiedResponse) def apply_friend( current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """申请好友:注册用户向博主发起好友申请。""" if current_user.role == ROLE_BLOGGER: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="博主无需申请好友") if current_user.role == ROLE_FRIEND: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="你们已经是好友") record = db.query(Friend).filter(Friend.user_id == current_user.id).first() if record is None: # 首次申请:新建待审批记录 record = Friend(user_id=current_user.id, status=FRIEND_STATUS_PENDING) db.add(record) elif record.status == FRIEND_STATUS_PENDING: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="申请已提交,请等待博主审批") elif record.status == FRIEND_STATUS_ACCEPTED: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="你们已经是好友") else: # 此前被拒绝:允许重新提交申请 record.status = FRIEND_STATUS_PENDING db.commit() db.refresh(record) return UnifiedResponse( success=True, data={"id": record.id, "status": record.status}, message="申请成功,等待博主审批", ) @router.get("/status", response_model=UnifiedResponse) def get_friend_status( current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """查询当前用户的好友状态:none / pending / accepted / rejected(博主返回 blogger)。""" if current_user.role == ROLE_BLOGGER: return UnifiedResponse(success=True, data={"status": "blogger"}, message="获取成功") if current_user.role == ROLE_FRIEND: return UnifiedResponse(success=True, data={"status": "accepted"}, message="获取成功") record = db.query(Friend).filter(Friend.user_id == current_user.id).first() status_value = record.status if record is not None else "none" return UnifiedResponse(success=True, data={"status": status_value}, message="获取成功") @router.get("/list", response_model=UnifiedResponse) def list_friends( current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """好友列表:博主查看全部已成为好友的用户;好友用户查看自己与博主的好友关系。""" if current_user.role not in (ROLE_BLOGGER, ROLE_FRIEND): raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="登录并成为好友后可查看好友列表") if current_user.role == ROLE_BLOGGER: # 博主视角:所有已通过的好友申请,申请人即好友 records = db.query(Friend).filter(Friend.status == FRIEND_STATUS_ACCEPTED).all() else: # 好友视角:自己那条已通过的申请,对应好友为博主 records = db.query(Friend).filter( Friend.user_id == current_user.id, Friend.status == FRIEND_STATUS_ACCEPTED, ).all() data = [] for record in records: member = ( db.query(User).filter(User.id == record.user_id).first() if current_user.role == ROLE_BLOGGER else db.query(User).filter(User.role == ROLE_BLOGGER).first() ) if member is None: continue data.append({ "id": member.id, "username": member.username, "avatar": member.avatar, "bio": member.bio, "friend_since": record.created_time, }) return UnifiedResponse(success=True, data=data, message="获取成功") @router.get("/applications", response_model=UnifiedResponse) def list_applications( current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """好友申请列表:仅博主可查看全部申请记录。""" if current_user.role != ROLE_BLOGGER: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="只有博主可以查看好友申请") records = db.query(Friend).order_by(Friend.id.asc()).all() data = [ { "id": r.id, "user_id": r.user_id, "username": r.user.username if r.user else None, "email": r.user.email if r.user else None, "status": r.status, "created_time": r.created_time, } for r in records ] return UnifiedResponse(success=True, data=data, message="获取成功") @router.post("/{friend_id}/approve", response_model=UnifiedResponse) def approve_friend( friend_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """审批通过好友申请:仅博主;通过后申请人角色提升为 friend。""" if current_user.role != ROLE_BLOGGER: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="只有博主可以审批好友申请") record = db.query(Friend).filter(Friend.id == friend_id).first() if record is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="好友申请不存在") if record.status != FRIEND_STATUS_PENDING: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="该申请已处理,不能重复审批") applicant = db.query(User).filter(User.id == record.user_id).first() record.status = FRIEND_STATUS_ACCEPTED if applicant is not None and applicant.role != ROLE_BLOGGER: applicant.role = ROLE_FRIEND db.commit() return UnifiedResponse( success=True, data={"id": record.id, "status": record.status}, message="已通过好友申请", ) @router.post("/{friend_id}/reject", response_model=UnifiedResponse) def reject_friend( friend_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ) -> UnifiedResponse: """拒绝好友申请:仅博主。""" if current_user.role != ROLE_BLOGGER: raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="只有博主可以审批好友申请") record = db.query(Friend).filter(Friend.id == friend_id).first() if record is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="好友申请不存在") if record.status != FRIEND_STATUS_PENDING: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="该申请已处理,不能重复操作") record.status = FRIEND_STATUS_REJECTED db.commit() return UnifiedResponse( success=True, data={"id": record.id, "status": record.status}, message="已拒绝好友申请", )