0841b1a103
- 前端:Vue3 + TS + Element Plus,24 个页面路由(课件/组题/教案/动画/思维导图/作文批改/命题/课堂/资源/社区等) - 后端:FastAPI + SQLAlchemy + SQLite,17 个路由模块,AI 服务层含降级模板 - AI:glm-5.x 推理模型已禁用思维链,确保输出真实内容 - 修复:ai_service 两处请求体注入 enable_thinking/thinking disabled - 测试账号:13900999999 / test1234
211 lines
8.0 KiB
Python
211 lines
8.0 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
from sqlalchemy import or_
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional
|
|
from database import get_db
|
|
from models.community import Post, Comment, PostFavorite
|
|
from models.user import User
|
|
from schemas.community import PostCreate, PostUpdate, PostOut, CommentCreate, CommentOut
|
|
from services.auth import get_current_user, get_optional_current_user
|
|
from routers.notification import push_notification
|
|
|
|
router = APIRouter(prefix="/api/community", tags=["教师社区"])
|
|
|
|
|
|
def _sync_post_favorite_count(post: Post, db: Session) -> None:
|
|
post.likes = db.query(PostFavorite).filter(PostFavorite.post_id == post.id).count()
|
|
|
|
|
|
def _serialize_post(post: Post, current_user: User | None, db: Session) -> Post:
|
|
is_favorited = False
|
|
if current_user:
|
|
is_favorited = db.query(PostFavorite).filter(
|
|
PostFavorite.user_id == current_user.id,
|
|
PostFavorite.post_id == post.id,
|
|
).first() is not None
|
|
setattr(post, "is_favorited", is_favorited)
|
|
setattr(post, "author", post.author)
|
|
return post
|
|
|
|
|
|
@router.post("/posts", response_model=PostOut, status_code=201)
|
|
def create_post(data: PostCreate, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
post = Post(user_id=current_user.id, **data.model_dump())
|
|
db.add(post)
|
|
db.commit()
|
|
db.refresh(post)
|
|
return _serialize_post(post, current_user, db)
|
|
|
|
|
|
@router.get("/posts", response_model=list[PostOut])
|
|
def list_posts(
|
|
post_type: Optional[str] = None,
|
|
keyword: Optional[str] = None,
|
|
scope: Optional[str] = None,
|
|
skip: int = Query(0, ge=0),
|
|
limit: int = Query(20, ge=1, le=100),
|
|
current_user: User | None = Depends(get_optional_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
query = db.query(Post)
|
|
if scope in {"mine", "favorite"} and not current_user:
|
|
raise HTTPException(status_code=401, detail="请先登录")
|
|
if scope == "mine":
|
|
query = query.filter(Post.user_id == current_user.id)
|
|
elif scope == "favorite":
|
|
query = query.join(PostFavorite, PostFavorite.post_id == Post.id).filter(
|
|
PostFavorite.user_id == current_user.id,
|
|
)
|
|
if post_type:
|
|
query = query.filter(Post.post_type == post_type)
|
|
if keyword:
|
|
query = query.filter(or_(
|
|
Post.title.contains(keyword),
|
|
Post.content.contains(keyword),
|
|
))
|
|
posts = query.order_by(Post.is_pinned.desc(), Post.created_at.desc()).offset(skip).limit(limit).all()
|
|
return [_serialize_post(post, current_user, db) for post in posts]
|
|
|
|
|
|
@router.get("/posts/ranking", response_model=list[PostOut])
|
|
def ranking_posts(
|
|
limit: int = Query(5, ge=1, le=20),
|
|
current_user: User | None = Depends(get_optional_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
score = Post.views + Post.likes * 10 + Post.comments_count * 3
|
|
posts = (
|
|
db.query(Post)
|
|
.order_by(Post.is_pinned.desc(), score.desc(), Post.created_at.desc())
|
|
.limit(limit)
|
|
.all()
|
|
)
|
|
return [_serialize_post(post, current_user, db) for post in posts]
|
|
|
|
|
|
@router.get("/posts/{post_id}", response_model=PostOut)
|
|
def get_post(
|
|
post_id: int,
|
|
current_user: User | None = Depends(get_optional_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
post.views = (post.views or 0) + 1
|
|
db.commit()
|
|
db.refresh(post)
|
|
return _serialize_post(post, current_user, db)
|
|
|
|
|
|
@router.put("/posts/{post_id}", response_model=PostOut)
|
|
def update_post(
|
|
post_id: int,
|
|
data: PostUpdate,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id, Post.user_id == current_user.id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
update_data = data.model_dump(exclude_unset=True)
|
|
for key, value in update_data.items():
|
|
setattr(post, key, value)
|
|
db.commit()
|
|
db.refresh(post)
|
|
return _serialize_post(post, current_user, db)
|
|
|
|
|
|
@router.post("/posts/{post_id}/like", response_model=dict)
|
|
def like_post(
|
|
post_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
favorite = db.query(PostFavorite).filter(
|
|
PostFavorite.user_id == current_user.id,
|
|
PostFavorite.post_id == post_id,
|
|
).first()
|
|
if not favorite:
|
|
db.add(PostFavorite(user_id=current_user.id, post_id=post_id))
|
|
db.flush()
|
|
push_notification(db, user_id=post.user_id, actor_id=current_user.id, ntype="like", title=f"{current_user.name} 收藏了你的帖子", content=post.title[:60], link=f"/community/{post_id}")
|
|
_sync_post_favorite_count(post, db)
|
|
db.commit()
|
|
return {"success": True, "likes": post.likes, "is_favorited": True}
|
|
|
|
|
|
@router.delete("/posts/{post_id}/like", response_model=dict)
|
|
def unlike_post(
|
|
post_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
favorite = db.query(PostFavorite).filter(
|
|
PostFavorite.user_id == current_user.id,
|
|
PostFavorite.post_id == post_id,
|
|
).first()
|
|
if favorite:
|
|
db.delete(favorite)
|
|
db.flush()
|
|
_sync_post_favorite_count(post, db)
|
|
db.commit()
|
|
return {"success": True, "likes": post.likes, "is_favorited": False}
|
|
|
|
|
|
@router.get("/posts/{post_id}/comments", response_model=list[CommentOut])
|
|
def list_comments(post_id: int, skip: int = Query(0, ge=0), limit: int = Query(50, ge=1, le=200), db: Session = Depends(get_db)):
|
|
return db.query(Comment).filter(Comment.post_id == post_id).order_by(Comment.created_at).offset(skip).limit(limit).all()
|
|
|
|
|
|
@router.post("/posts/{post_id}/comments", response_model=CommentOut, status_code=201)
|
|
def create_comment(
|
|
post_id: int, data: CommentCreate,
|
|
current_user: User = Depends(get_current_user), db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
comment = Comment(post_id=post_id, user_id=current_user.id, **data.model_dump())
|
|
db.add(comment)
|
|
post.comments_count = (post.comments_count or 0) + 1
|
|
push_notification(db, user_id=post.user_id, actor_id=current_user.id, ntype="comment", title=f"{current_user.name} 评论了你的帖子", content=post.title[:60], link=f"/community/{post_id}")
|
|
db.commit()
|
|
db.refresh(comment)
|
|
return comment
|
|
|
|
|
|
@router.delete("/posts/{post_id}/comments/{comment_id}", status_code=204)
|
|
def delete_comment(
|
|
post_id: int,
|
|
comment_id: int,
|
|
current_user: User = Depends(get_current_user),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
post = db.query(Post).filter(Post.id == post_id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
comment = db.query(Comment).filter(Comment.id == comment_id, Comment.post_id == post_id).first()
|
|
if not comment:
|
|
raise HTTPException(status_code=404, detail="评论不存在")
|
|
if comment.user_id != current_user.id and post.user_id != current_user.id:
|
|
raise HTTPException(status_code=403, detail="无权删除该评论")
|
|
db.delete(comment)
|
|
post.comments_count = max((post.comments_count or 0) - 1, 0)
|
|
db.commit()
|
|
|
|
|
|
@router.delete("/posts/{post_id}", status_code=204)
|
|
def delete_post(post_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db)):
|
|
post = db.query(Post).filter(Post.id == post_id, Post.user_id == current_user.id).first()
|
|
if not post:
|
|
raise HTTPException(status_code=404, detail="帖子不存在")
|
|
db.delete(post)
|
|
db.commit()
|