feat:增加上传博客图片模块
This commit is contained in:
11
api/blog.py
11
api/blog.py
@@ -1,6 +1,6 @@
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from fastapi import APIRouter, Depends, Query, Request, UploadFile, File
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from config.auth import verify_token
|
||||
@@ -10,7 +10,7 @@ from schemas.blog import BlogResponse, BlogQuery, BlogCategoryResponse, BlogStat
|
||||
from schemas.blog_elastic import BlogSearch
|
||||
from schemas.pagination import PageResult
|
||||
from config.database import get_db
|
||||
from service import blog_service, blog_elastic_service
|
||||
from service import blog_service, blog_elastic_service, file_service
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/blog",
|
||||
@@ -19,6 +19,11 @@ router = APIRouter(
|
||||
)
|
||||
|
||||
|
||||
@router.post("/file/upload", summary="上传博客图片", response_model=str)
|
||||
async def sync_all_blog(md5: str, file: UploadFile = File(...)):
|
||||
return await file_service.upload_file(md5, file)
|
||||
|
||||
|
||||
@router.get("/sync", summary="同步博客到elastic", response_model=bool)
|
||||
def sync_all_blog(db: Session = Depends(get_db)):
|
||||
return blog_elastic_service.sync_all_blog(db)
|
||||
@@ -46,12 +51,14 @@ 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)):
|
||||
return blog_service.add_blog(db, blog)
|
||||
|
||||
15
config/rustfs.py
Normal file
15
config/rustfs.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import boto3
|
||||
from botocore.client import Config
|
||||
|
||||
from config.setting import settings
|
||||
|
||||
access_key = 'jRxroVX8PUuSOia71qE4'
|
||||
secret_access = 'RZE82VATN1Gqj9xy3d5OzFvHoDBgwJ4PSf7IKuei'
|
||||
|
||||
s3 = boto3.client('s3',
|
||||
endpoint_url=f'http://{settings.RUSTFS_HOST}:{settings.RUSTFS_PORT}',
|
||||
aws_access_key_id=access_key,
|
||||
aws_secret_access_key=secret_access,
|
||||
config=Config(signature_version='s3v4'),
|
||||
region_name='cn-east-1'
|
||||
)
|
||||
@@ -8,6 +8,8 @@ class Settings(BaseSettings):
|
||||
DB_PASSWORD: str
|
||||
ES_HOST: str
|
||||
FLUENTD_HOST: str
|
||||
RUSTFS_HOST:str
|
||||
RUSTFS_PORT: str
|
||||
|
||||
class Config:
|
||||
env_file = ".env" # 指定.env文件路径
|
||||
|
||||
@@ -1 +1 @@
|
||||
fastapi~=0.115.12
|
||||
fastapi~=0.115.12
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,12 @@ def sync_all_blog(db: Session) -> bool:
|
||||
if settings.ENVIRONMENT == 'dev':
|
||||
return True
|
||||
|
||||
query = select(
|
||||
stmt = select(
|
||||
Blog.id,
|
||||
Blog.title,
|
||||
BlogCategory.name.label("category"),
|
||||
BlogContent.content.label("content"),
|
||||
Blog.is_approved.label("isApproved"),
|
||||
Blog.create_time.label("createTime"),
|
||||
Blog.update_time.label("updateTime"),
|
||||
).select_from(Blog).outerjoin(
|
||||
@@ -29,7 +30,7 @@ def sync_all_blog(db: Session) -> bool:
|
||||
).outerjoin(
|
||||
BlogContent, Blog.content_id == BlogContent.id
|
||||
)
|
||||
results = db.execute(query).fetchall()
|
||||
results = db.execute(stmt).fetchall()
|
||||
|
||||
actions = [
|
||||
{
|
||||
@@ -40,6 +41,7 @@ def sync_all_blog(db: Session) -> bool:
|
||||
"title": blog.title,
|
||||
"category": blog.category,
|
||||
"content": blog.content.decode("utf-8"),
|
||||
"isApproved": blog.isApproved,
|
||||
"createTime": blog.createTime.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"updateTime": blog.updateTime.strftime("%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
@@ -106,10 +108,23 @@ def search_blog(keyword: str) -> List[BlogSearch]:
|
||||
# 构造查询请求
|
||||
body = {
|
||||
"query": {
|
||||
"multi_match": {
|
||||
"query": keyword,
|
||||
"fields": ["title^3", "content"],
|
||||
"type": "phrase"
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"multi_match": {
|
||||
"query": keyword,
|
||||
"fields": ["title^3", "content"],
|
||||
"type": "phrase"
|
||||
}
|
||||
}
|
||||
],
|
||||
"filter": [
|
||||
{
|
||||
"term": {
|
||||
"isApproved": 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"highlight": {
|
||||
|
||||
40
service/file_service.py
Normal file
40
service/file_service.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from fastapi import UploadFile, File, HTTPException
|
||||
|
||||
from config.rustfs import s3
|
||||
from config.setting import settings
|
||||
|
||||
ALLOWED_IMAGE_TYPES = [
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/webp",
|
||||
"image/svg+xml",
|
||||
]
|
||||
|
||||
BUCKET = 'blog'
|
||||
NGINX_PROXY = 'rustfs'
|
||||
|
||||
|
||||
async def upload_file(md5: str, file: UploadFile = File(...)) -> str:
|
||||
# 校验文件类型是否是图片
|
||||
if file.content_type not in ALLOWED_IMAGE_TYPES:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="只允许上传图片文件 (JPEG, PNG, GIF, WEBP, SVG)"
|
||||
)
|
||||
|
||||
file_ext = file.filename.split('.')[-1]
|
||||
unique_filename = f"{md5}.{file_ext}"
|
||||
|
||||
file_content = await file.read()
|
||||
|
||||
# 上传到S3
|
||||
s3.put_object(
|
||||
Bucket=BUCKET,
|
||||
Key=unique_filename,
|
||||
Body=file_content,
|
||||
ContentType=file.content_type
|
||||
)
|
||||
|
||||
# 返回文件url
|
||||
return f"{NGINX_PROXY}/{BUCKET}/{unique_filename}"
|
||||
Reference in New Issue
Block a user