from typing import List from fastapi import Request from sqlalchemy import select, func, desc, and_, asc, delete from sqlalchemy.orm import Session from models.blog import Blog, BlogCategory, BlogVisit, BlogContent, BlogComment from schemas.blog import BlogResponse, BlogQuery, BlogCategoryResponse, BlogStatsResponse, \ BlogLatestResponse, BlogCommentCreate, BlogCommentResponse, BlogVisitResponse, BlogCreate, BlogUpdate, \ BlogAdjacentResponse from schemas.blog_elastic import BlogElastic from schemas.pagination import PageResult from schemas.paginate_query import paginate_query from middleware.exceptions import AppException 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, is_all=False) -> PageResult[BlogResponse]: stmt = (select( Blog.id, Blog.title, Blog.top_value.label("topValue"), Blog.is_great.label("isGreat"), BlogCategory.name.label("category"), Blog.summary, 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") ).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))) 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]: stmt = (select( Blog.id, Blog.title, Blog.top_value.label("topValue"), Blog.is_great.label("isGreat"), BlogCategory.name.label("category"), Blog.summary, 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") ).where(Blog.is_approved == 1) .outerjoin(BlogCategory, Blog.category_id == BlogCategory.id) .outerjoin(BlogContent, Blog.content_id == BlogContent.id)) conditions = [] if blog_query.category: conditions.append(BlogCategory.name == blog_query.category) if blog_query.title: conditions.append(Blog.title.like(f"%{blog_query.title}%")) if blog_query.year: conditions.append(func.extract('year', Blog.create_time) == blog_query.year) if conditions: stmt = stmt.where(and_(*conditions)) stmt = stmt.order_by(desc(Blog.update_time)) results = db.execute(stmt).fetchall() return [BlogResponse.from_orm(result) for result in results] def query_blog_by_id(db: Session, blog_id: int) -> BlogResponse: check_blog_exist(db, blog_id) stmt = (select( Blog.id.label("id"), Blog.title.label("title"), Blog.top_value.label("topValue"), Blog.is_great.label("isGreat"), BlogCategory.name.label("category"), Blog.summary.label("summary"), BlogContent.content.label("content"), 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") ).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 = db.execute(stmt).first() return BlogResponse.from_orm(blog) def add_blog(db: Session, blog: BlogCreate) -> bool: word_count = get_word_count(blog.content) db_blog = Blog( title=blog.title, top_value=blog.topValue, is_great=blog.isGreat, category_id=add_blog_category(db, blog.category), 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), is_approved=blog.isApproved ) db.add(db_blog) db.commit() db.refresh(db_blog) blog_elastic = BlogElastic( id=db_blog.id, title=db_blog.title, content=blog.content, category=blog.category, isApproved=blog.isApproved ) add_blog_elastic(blog_elastic) return True def add_blog_category(db: Session, category: str) -> int: db_blog_category = db.execute(select(BlogCategory).where(BlogCategory.name == category)).scalar_one_or_none() if db_blog_category is None: db_new_blog_category = BlogCategory(name=category) db.add(db_new_blog_category) db.commit() category_id = db_new_blog_category.id else: category_id = db_blog_category.id return category_id def add_blog_content(db: Session, content: str) -> int: db_blog_content = BlogContent(content=content.encode('utf-8')) db.add(db_blog_content) db.commit() return db_blog_content.id def update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool: db_blog = check_blog_exist(db, blog_id) update_data = blog.model_dump(exclude_unset=True) update_blog_content(db, db_blog.content_id, blog.content) db_blog.title = update_data["title"] db_blog.top_value = update_data["topValue"] db_blog.is_great = update_data["isGreat"] db_blog.category_id = update_blog_category(db, blog.category) word_count = get_word_count(blog.content) 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) return True def update_blog_category(db: Session, category: str) -> int: db_blog_category = db.execute(select(BlogCategory).where(BlogCategory.name == category)).scalar_one_or_none() if db_blog_category is None: return add_blog_category(db, category) else: return db_blog_category.id def update_blog_content(db: Session, blog_content_id: int, blog_content: str) -> bool: db_blog_content = check_blog_content_exist(db, blog_content_id) db_blog_content.content = blog_content.encode('utf-8') db.commit() db.refresh(db_blog_content) return True def delete_blog(db: Session, blog_id: int) -> bool: db_blog = check_blog_exist(db, blog_id) delete_blog_content(db, db_blog.content_id) db.execute(delete(Blog).where(Blog.id == blog_id)) db.commit() return True def delete_blog_content(db: Session, blog_content_id: int) -> bool: check_blog_content_exist(db, blog_content_id) db.execute(delete(BlogContent).where(BlogContent.id == blog_content_id)) db.commit() return True def query_blog_category(db: Session) -> List[BlogCategoryResponse]: 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() return [BlogCategoryResponse.from_orm(result) for result in results] def query_blog_stats(db: Session) -> BlogStatsResponse: return BlogStatsResponse( blogCount=db.query(Blog).count(), categoryCount=db.query(BlogCategory).count(), wordCount=db.query(func.sum(Blog.word_count)).scalar() ) def query_blog_latest(db: Session) -> List[BlogLatestResponse]: 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] def query_blog_adjacent(db: Session, blog_id: int) -> List[BlogAdjacentResponse]: check_blog_exist(db, blog_id) 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_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( id=prev_result[0] if prev_result else 0, title=prev_result[1] if prev_result else "" ), BlogAdjacentResponse( id=next_result[0] if next_result else 0, title=next_result[1] if next_result else "" ) ] def add_blog_visit(db: Session, blog_visit: BlogVisit): db.add(blog_visit) db.commit() db.refresh(blog_visit) def query_blog_visit(db: Session, current_page: int = 1, page_size: int = 10) -> PageResult[BlogVisitResponse]: query = select( BlogVisit.ip, BlogVisit.os, BlogVisit.browser, BlogVisit.uri, Blog.title, BlogVisit.create_time.label("visitTime") ).select_from(BlogVisit).outerjoin( Blog, Blog.id == BlogVisit.blog_id ).order_by(desc(BlogVisit.create_time)) return paginate_query(db, query, current_page, page_size) def query_blog_comment(db: Session, blog_id: int) -> List[BlogCommentResponse]: stmt = select( BlogComment.id, BlogComment.blog_id.label("blogId"), BlogComment.parent_id.label("parentId"), BlogComment.name, BlogComment.website, BlogComment.ip_address.label("ipAddress"), BlogComment.user_agent.label("userAgent"), BlogComment.content, BlogComment.is_approved.label("isApproved"), BlogComment.create_time.label("createTime") ).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] def add_blog_comment(db: Session, request: Request, blog_id: int, blog_comment: BlogCommentCreate) -> bool: check_blog_exist(db, blog_id) if blog_comment.parentId != 0: parent_comment = db.execute( select(BlogComment) .where(BlogComment.id == blog_comment.parentId) .where(BlogComment.blog_id == blog_id) ).scalar_one_or_none() if not parent_comment: raise AppException("父评论不存在") db_comment = BlogComment( blog_id=blog_id, parent_id=blog_comment.parentId, name=blog_comment.name, website=blog_comment.website, content=blog_comment.content, ip_address=request.client.host, user_agent=request.headers.get("user-agent"), is_approved=1 ) db.add(db_comment) db.commit() db.refresh(db_comment) return True def check_blog_exist(db: Session, blog_id: int) -> Blog: result = db.execute(select(Blog).where(Blog.id == blog_id)).scalar_one_or_none() if not result: raise AppException("博客不存在") return result def check_blog_content_exist(db: Session, blog_content_id: int) -> BlogContent: result = db.execute(select(BlogContent).where(BlogContent.id == blog_content_id)).scalar_one_or_none() if not result: raise AppException("博客内容不存在") return result