379 lines
12 KiB
Python
379 lines
12 KiB
Python
from typing import List
|
|
|
|
from fastapi import Request
|
|
from sqlalchemy import select, func, desc, and_, asc
|
|
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 service.blog_stats_service import query_blog_overview
|
|
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,
|
|
Blog.is_great,
|
|
BlogCategory.name.label("category"),
|
|
Blog.summary,
|
|
Blog.word_count,
|
|
Blog.read_duration,
|
|
func.count(BlogVisit.id).label("visitCount"),
|
|
Blog.is_approved,
|
|
Blog.create_time,
|
|
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.is_great), 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 = get_query_blog_by_condition_stmt(blog_query)
|
|
results = db.execute(stmt).fetchall()
|
|
return [BlogResponse.model_validate(result) for result in results]
|
|
|
|
|
|
def get_query_blog_by_condition_stmt(blog_query: BlogQuery):
|
|
stmt = (select(
|
|
Blog.id,
|
|
Blog.title,
|
|
Blog.top_value,
|
|
Blog.is_great,
|
|
BlogCategory.name.label("category"),
|
|
Blog.summary,
|
|
BlogContent.content,
|
|
Blog.word_count,
|
|
Blog.read_duration,
|
|
func.count(BlogVisit.id).label("visitCount"),
|
|
Blog.is_approved,
|
|
Blog.create_time,
|
|
Blog.update_time
|
|
).where(Blog.is_approved == 1)
|
|
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
|
.outerjoin(BlogContent, Blog.content_id == BlogContent.id)
|
|
.outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id)
|
|
.group_by(Blog.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.is_great), desc(Blog.update_time))
|
|
|
|
return stmt
|
|
|
|
|
|
def query_blog_by_condition_page(db: Session, blog_query: BlogQuery,
|
|
current_page: int = 1, page_size: int = 10) -> PageResult[BlogResponse]:
|
|
stmt = get_query_blog_by_condition_stmt(blog_query)
|
|
return paginate_query(db, stmt, current_page, page_size)
|
|
|
|
|
|
def query_unapproved_blog(db: Session) -> List[BlogResponse]:
|
|
stmt = ((select(
|
|
Blog.id,
|
|
Blog.title,
|
|
Blog.top_value,
|
|
Blog.is_great,
|
|
BlogCategory.name.label("category"),
|
|
Blog.summary,
|
|
BlogContent.content,
|
|
Blog.word_count,
|
|
Blog.read_duration,
|
|
func.count(BlogVisit.id),
|
|
Blog.is_approved,
|
|
Blog.create_time,
|
|
Blog.update_time
|
|
).where(Blog.is_approved == 0)
|
|
.outerjoin(BlogCategory, Blog.category_id == BlogCategory.id)
|
|
.outerjoin(BlogContent, Blog.content_id == BlogContent.id))
|
|
.outerjoin(BlogVisit, Blog.id == BlogVisit.blog_id)
|
|
.group_by(Blog.id)
|
|
.order_by(desc(Blog.update_time)))
|
|
|
|
results = db.execute(stmt).fetchall()
|
|
|
|
return [BlogResponse.model_validate(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,
|
|
Blog.title,
|
|
Blog.top_value,
|
|
Blog.is_great,
|
|
BlogCategory.name.label("category"),
|
|
Blog.summary,
|
|
BlogContent.content,
|
|
Blog.word_count,
|
|
Blog.read_duration,
|
|
func.count(BlogVisit.id).label("visitCount"),
|
|
Blog.is_approved,
|
|
Blog.create_time,
|
|
Blog.update_time
|
|
).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.model_validate(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.top_value,
|
|
is_great=blog.is_great,
|
|
category_id=add_blog_category(db, blog.category),
|
|
summary=get_blog_summary(blog.content),
|
|
word_count=word_count,
|
|
read_duration=get_read_duration(word_count),
|
|
is_approved=blog.is_approved
|
|
)
|
|
|
|
# 级联新增
|
|
db_blog.content = BlogContent(content=blog.content.encode('utf-8'))
|
|
|
|
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 update_blog(db: Session, blog_id: int, blog: BlogUpdate) -> bool:
|
|
db_blog = check_blog_exist(db, blog_id)
|
|
|
|
db_blog.title = blog.title
|
|
db_blog.top_value = blog.topValue
|
|
db_blog.is_great = blog.isGreat
|
|
db_blog.category_id = update_blog_category(db, blog.category)
|
|
|
|
# 级联更新
|
|
db_blog.content = BlogContent(content=blog.content.encode('utf-8'))
|
|
|
|
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 delete_blog(db: Session, blog_id: int) -> bool:
|
|
db_blog = check_blog_exist(db, blog_id)
|
|
|
|
# 级联删除
|
|
db.delete(db_blog)
|
|
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.model_validate(result) for result in results]
|
|
|
|
|
|
def query_blog_stats(db: Session) -> BlogStatsResponse:
|
|
blog_stats = query_blog_overview(db)
|
|
|
|
return BlogStatsResponse(
|
|
blogCount=blog_stats.blogCount,
|
|
categoryCount=blog_stats.categoryCount,
|
|
wordCount=blog_stats.wordCount
|
|
)
|
|
|
|
|
|
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.model_validate(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,
|
|
BlogComment.parent_id,
|
|
BlogComment.name,
|
|
BlogComment.website,
|
|
BlogComment.ip_address,
|
|
BlogComment.user_agent,
|
|
BlogComment.content,
|
|
BlogComment.is_approved,
|
|
BlogComment.create_time
|
|
).where(BlogComment.blog_id == blog_id, BlogComment.is_approved == 1).order_by(desc(BlogComment.create_time))
|
|
results = db.execute(stmt).fetchall()
|
|
|
|
return [BlogCommentResponse.model_validate(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=True
|
|
)
|
|
|
|
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
|