Initial commit: MyBlog full stack blog

This commit is contained in:
2026-08-22 22:28:41 +08:00
commit c61193f2af
64 changed files with 7290 additions and 0 deletions
+191
View File
@@ -0,0 +1,191 @@
"""
好友路由。
按“用户向博主申请、博主审批”实现(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="已拒绝好友申请",
)