diff --git a/api/blog.py b/api/blog.py index 2d32ca8..4e038dd 100644 --- a/api/blog.py +++ b/api/blog.py @@ -46,6 +46,11 @@ def query_blog_by_condition(query: BlogQuery = Depends(), def query_blog_by_id(blog_id: int, db: Session = Depends(get_db)): return blog_service.query_blog_by_id(db, blog_id) +@router.get("/all/page", summary="分页查询博客", response_model=PageResult[BlogResponse]) +def query_blog_by_page(current_page: int = Query(1, ge=1, alias="currentPage", description="当前页码"), + page_size: int = Query(10, ge=1, le=100, alias="pageSize", description="每页数量"), + db: Session = Depends(get_db), _=Depends(verify_token)): + return blog_service.query_blog_by_page(db, current_page, page_size, True) @router.post("", summary="新增博客内容", response_model=bool) def add_blog(blog: BlogCreate, db: Session = Depends(get_db), _=Depends(verify_token)): diff --git a/blog.sql b/blog.sql new file mode 100644 index 0000000..c17cc80 --- /dev/null +++ b/blog.sql @@ -0,0 +1,157 @@ +-- MySQL dump 10.13 Distrib 8.0.26, for Win64 (x86_64) +-- +-- Host: localhost Database: blog +-- ------------------------------------------------------ +-- Server version 8.0.27 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `blog` +-- + +DROP TABLE IF EXISTS `blog`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog` ( + `id` bigint NOT NULL, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '博客标题', + `top_value` int NOT NULL COMMENT '置顶值 越大越靠前', + `is_great` tinyint NOT NULL COMMENT '是否是精品 0否1是', + `category_id` bigint NOT NULL COMMENT '博客类别', + `summary` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '博客内容概要', + `content_id` bigint NOT NULL COMMENT '博客内容', + `word_count` int NOT NULL COMMENT '字数统计', + `read_duration` decimal(10,2) NOT NULL COMMENT '阅读时长', + `is_approved` tinyint NOT NULL COMMENT '是否发布', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '发布时间', + `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '发布人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='博客记录'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `blog_category` +-- + +DROP TABLE IF EXISTS `blog_category`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_category` ( + `id` bigint NOT NULL, + `name` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类别名称', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '更新人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='博客类别'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `blog_comment` +-- + +DROP TABLE IF EXISTS `blog_comment`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_comment` ( + `id` bigint NOT NULL COMMENT 'id', + `blog_id` bigint NOT NULL COMMENT '博客id', + `parent_id` bigint NOT NULL COMMENT '父评论id', + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评论人昵称', + `website` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '评论人网站', + `ip_address` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评论人ip', + `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评论人浏览器信息', + `content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '评论内容', + `is_approved` tinyint NOT NULL COMMENT '是否通过', + `create_time` datetime DEFAULT NULL COMMENT '评论时间', + `create_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='博客评论'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `blog_content` +-- + +DROP TABLE IF EXISTS `blog_content`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_content` ( + `id` bigint NOT NULL, + `content` mediumblob NOT NULL COMMENT '博客内容', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='博客内容'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `blog_like` +-- + +DROP TABLE IF EXISTS `blog_like`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_like` ( + `id` bigint NOT NULL COMMENT 'id', + `user_id` bigint DEFAULT NULL COMMENT '点赞人', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '点赞类型(博客、评论)', + `target_id` bigint DEFAULT NULL COMMENT '点赞目标的id', + `status` tinyint DEFAULT NULL COMMENT '点赞状态 0取消点赞/1点赞', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='博客点赞'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `blog_visit` +-- + +DROP TABLE IF EXISTS `blog_visit`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `blog_visit` ( + `id` bigint NOT NULL, + `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ip地址', + `os` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作系统', + `browser` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '浏览器', + `uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '路径', + `blog_id` bigint DEFAULT NULL COMMENT '博客id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='博客访问记录'; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping routines for database 'blog' +-- +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2025-10-23 19:56:43 diff --git a/middleware/exceptions.py b/middleware/exceptions.py index 8013846..4b3beb6 100644 --- a/middleware/exceptions.py +++ b/middleware/exceptions.py @@ -35,13 +35,13 @@ async def global_exception_handler(request: Request, call_next): except SQLAlchemyError as e: # 记录数据库异常 - logger.critical(f"数据库异常: {str(e)}", exc_info=True) + logger.critical(f"数据库异常: {str(e)}") return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"message": "数据库操作失败", "details": str(e)}) except Exception as e: # 记录未知异常(带堆栈信息) - logger.critical(f"未知异常: {str(e)}", exc_info=True) + logger.critical(f"未知异常: {str(e)}") return JSONResponse(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, content={"code": 500, "message": "服务器内部错误", "details": str(e)}) diff --git a/models/blog.py b/models/blog.py index 0d2fcf9..a498148 100644 --- a/models/blog.py +++ b/models/blog.py @@ -22,6 +22,7 @@ class Blog(AuditBase): content_id = Column(BigInteger, nullable=True, comment="博客内容") word_count = Column(Integer, nullable=True, comment="字数统计") read_duration = Column(DECIMAL(10, 2), nullable=True, comment="阅读时长") + is_approved = Column(SMALLINT, nullable=True, comment="是否发布") category = relationship( "BlogCategory", @@ -83,14 +84,14 @@ class BlogVisit(AuditBase): class BlogComment(AuditBase): - blog_id = Column(BigInteger, comment="博客id") - parent_id = Column(BigInteger, comment="父评论id") - name = Column(String(255), comment="评论人昵称") + blog_id = Column(BigInteger, nullable=True, comment="博客id") + parent_id = Column(BigInteger, nullable=True, comment="父评论id") + name = Column(String(255), nullable=True, comment="评论人昵称") website = Column(String(255), nullable=True, comment="评论人网站") ip_address = Column(String(45), nullable=True, comment="评论人ip") user_agent = Column(String(255), nullable=True, comment="评论人浏览器信息") - content = Column(String(512), comment="评论内容") - is_approved = Column(SMALLINT, comment="是否通过") + content = Column(String(512), nullable=True, comment="评论内容") + is_approved = Column(SMALLINT, nullable=True, comment="是否通过") blog = relationship( "Blog", diff --git a/schemas/blog.py b/schemas/blog.py index 817748e..0c93716 100644 --- a/schemas/blog.py +++ b/schemas/blog.py @@ -19,6 +19,7 @@ class BlogBase(BaseModel): isGreat: bool category: str content: Optional[str] = None + isApproved: int class BlogCreate(BlogBase): diff --git a/schemas/blog_elastic.py b/schemas/blog_elastic.py index 981b12a..09aae3f 100644 --- a/schemas/blog_elastic.py +++ b/schemas/blog_elastic.py @@ -9,6 +9,7 @@ class BlogElastic(BaseModel): title: str content: str category: str + isApproved: int createTime: Optional[Union[datetime, str]] = None updateTime: Optional[Union[datetime, str]] = None diff --git a/service/blog_service.py b/service/blog_service.py index 596c438..e9a39e4 100644 --- a/service/blog_service.py +++ b/service/blog_service.py @@ -16,8 +16,9 @@ from service.blog_elastic_service import add_blog_elastic from utils.blog_utils import get_blog_summary, get_word_count, get_read_duration -def query_blog_by_page(db: Session, current_page: int = 1, page_size: int = 10) -> PageResult[BlogResponse]: - query = select( +def query_blog_by_page(db: Session, current_page: int = 1, page_size: int = 10, + is_all=False) -> PageResult[BlogResponse]: + stmt = (select( Blog.id, Blog.title, Blog.top_value.label("topValue"), @@ -27,23 +28,22 @@ def query_blog_by_page(db: Session, current_page: int = 1, page_size: int = 10) Blog.word_count.label("wordCount"), Blog.read_duration.label("readDuration"), func.count(BlogVisit.id).label("visitCount"), + Blog.is_approved.label("isApproved"), Blog.create_time.label("createTime"), Blog.update_time.label("updateTime") - ).select_from(Blog).outerjoin( - BlogCategory, Blog.category_id == BlogCategory.id - ).outerjoin( - BlogVisit, Blog.id == BlogVisit.blog_id - ).group_by( - Blog.id, BlogCategory.name - ).order_by( - desc(Blog.top_value), desc(Blog.update_time) - ) + ).outerjoin(BlogCategory, Blog.category_id == BlogCategory.id) + .outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id) + .group_by(Blog.id, BlogCategory.name) + .order_by(desc(Blog.top_value), desc(Blog.update_time))) - return paginate_query(db, query, current_page, page_size) + if not is_all: + stmt = stmt.where(Blog.is_approved == 1) + + return paginate_query(db, stmt, current_page, page_size) def query_blog_by_condition(db: Session, blog_query: BlogQuery) -> List[BlogResponse]: - query = select( + stmt = (select( Blog.id, Blog.title, Blog.top_value.label("topValue"), @@ -53,13 +53,12 @@ def query_blog_by_condition(db: Session, blog_query: BlogQuery) -> List[BlogResp BlogContent.content.label("content"), Blog.word_count.label("wordCount"), Blog.read_duration.label("readDuration"), + Blog.is_approved.label("isApproved"), Blog.create_time.label("createTime"), Blog.update_time.label("updateTime") - ).select_from(Blog).outerjoin( - BlogCategory, Blog.category_id == BlogCategory.id - ).outerjoin( - BlogContent, Blog.content_id == BlogContent.id - ) + ).where(Blog.is_approved == 1) + .outerjoin(BlogCategory, Blog.category_id == BlogCategory.id) + .outerjoin(BlogContent, Blog.content_id == BlogContent.id)) conditions = [] @@ -73,11 +72,11 @@ def query_blog_by_condition(db: Session, blog_query: BlogQuery) -> List[BlogResp conditions.append(func.extract('year', Blog.create_time) == blog_query.year) if conditions: - query = query.where(and_(*conditions)) + stmt = stmt.where(and_(*conditions)) - query = query.order_by(desc(Blog.update_time)) + stmt = stmt.order_by(desc(Blog.update_time)) - results = db.execute(query).fetchall() + results = db.execute(stmt).fetchall() return [BlogResponse.from_orm(result) for result in results] @@ -85,7 +84,7 @@ def query_blog_by_condition(db: Session, blog_query: BlogQuery) -> List[BlogResp def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse: check_blog_exist(db, blog_id) - query = db.query( + stmt = (select( Blog.id.label("id"), Blog.title.label("title"), Blog.top_value.label("topValue"), @@ -96,17 +95,15 @@ def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse: Blog.word_count.label("wordCount"), Blog.read_duration.label("readDuration"), func.count(BlogVisit.id).label("visitCount"), + Blog.is_approved.label("isApproved"), Blog.create_time.label("createTime"), Blog.update_time.label("updateTime") - ).select_from(Blog).outerjoin( - BlogCategory, Blog.category_id == BlogCategory.id - ).outerjoin( - BlogContent, Blog.content_id == BlogContent.id - ).outerjoin( - BlogVisit, Blog.id == BlogVisit.blog_id - ).filter(Blog.id == blog_id) + ).where(Blog.id == blog_id) + .outerjoin(BlogCategory, Blog.category_id == BlogCategory.id) + .outerjoin(BlogContent, Blog.content_id == BlogContent.id) + .outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id)) - blog = query.first() + blog = db.execute(stmt).first() return BlogResponse.from_orm(blog) @@ -122,7 +119,8 @@ def add_blog(db: Session, blog: BlogCreate) -> bool: content_id=add_blog_content(db, blog.content), summary=get_blog_summary(blog.content), word_count=word_count, - read_duration=get_read_duration(word_count) + read_duration=get_read_duration(word_count), + is_approved=blog.isApproved ) db.add(db_blog) @@ -133,7 +131,8 @@ def add_blog(db: Session, blog: BlogCreate) -> bool: id=db_blog.id, title=db_blog.title, content=blog.content, - category=blog.category + category=blog.category, + isApproved=blog.isApproved ) add_blog_elastic(blog_elastic) @@ -178,6 +177,7 @@ def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool: db_blog.summary = get_blog_summary(blog.content), db_blog.word_count = word_count db_blog.read_duration = get_read_duration(word_count) + db_blog.is_approved = blog.isApproved db.commit() db.refresh(db_blog) @@ -224,14 +224,10 @@ def delete_blog_content(db: Session, blog_content_id: int) -> bool: def query_blog_category(db: Session) -> List[BlogCategoryResponse]: - query = select( - BlogCategory.name, - func.count(Blog.id).label("count") - ).select_from(Blog).outerjoin( - BlogCategory, Blog.category_id == BlogCategory.id - ).group_by( - BlogCategory.name - ) + query = (select(BlogCategory.name, func.count(Blog.id).label("count")) + .where(Blog.is_approved == 1) + .outerjoin(BlogCategory, Blog.category_id == BlogCategory.id) + .group_by(BlogCategory.name)) results = db.execute(query).fetchall() @@ -247,12 +243,8 @@ def query_blog_stats(db: Session) -> BlogStatsResponse: def query_blog_latest(db: Session) -> List[BlogLatestResponse]: - query = select( - Blog.id, - Blog.title - ).select_from(Blog).order_by(desc(Blog.update_time)).limit(5) - - results = db.execute(query).fetchall() + stmt = select(Blog.id, Blog.title).where(Blog.is_approved == 1).order_by(desc(Blog.update_time)).limit(5) + results = db.execute(stmt).fetchall() return [BlogLatestResponse.from_orm(result) for result in results] @@ -260,19 +252,15 @@ def query_blog_latest(db: Session) -> List[BlogLatestResponse]: def query_blog_adjacent(db: Session, blog_id: int) -> List[BlogAdjacentResponse]: check_blog_exist(db, blog_id) - prev_result = db.execute( - select(Blog.id, Blog.title) - .where(Blog.id < blog_id) - .order_by(desc(Blog.id)) - .limit(1) - ).first() + prev_stmt = (select(Blog.id, Blog.title) + .where(Blog.id < blog_id, Blog.is_approved == 1) + .order_by(desc(Blog.id))) + prev_result = db.execute(prev_stmt).first() - next_result = db.execute( - select(Blog.id, Blog.title) - .where(Blog.id > blog_id) - .order_by(asc(Blog.id)) - .limit(1) - ).first() + next_stmt = (select(Blog.id, Blog.title) + .where(Blog.id > blog_id, Blog.is_approved == 1) + .order_by(asc(Blog.id))) + next_result = db.execute(next_stmt).first() return [ BlogAdjacentResponse( @@ -308,7 +296,7 @@ def query_blog_visit(db: Session, current_page: int = 1, page_size: int = 10) -> def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]: - query = select( + stmt = select( BlogComment.id, BlogComment.blog_id.label("blogId"), BlogComment.parent_id.label("parentId"), @@ -319,8 +307,8 @@ def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]: BlogComment.content, BlogComment.is_approved.label("isApproved"), BlogComment.create_time.label("createTime") - ).select_from(BlogComment).where(BlogComment.blog_id == blog_id) - results = db.execute(query).fetchall() + ).where(BlogComment.blog_id == blog_id, BlogComment.is_approved == 1).order_by(desc(BlogComment.create_time)) + results = db.execute(stmt).fetchall() return [BlogCommentResponse.from_orm(result) for result in results]