This commit is contained in:
2026-04-16 20:21:44 +08:00
parent 9d8467214a
commit 66f9f8fb72
+103
View File
@@ -0,0 +1,103 @@
import uuid
import boto3
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy import create_engine, Column, String, ForeignKey
from sqlalchemy.orm import sessionmaker, Session, declarative_base, relationship
from app.config import settings
# --- 数据库初始化 ---
engine = create_engine(settings.database_url)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# --- S3 客户端初始化 ---
s3_client = boto3.client(
's3',
aws_access_key_id=settings.s3_access_key,
aws_secret_access_key=settings.s3_secret_key,
endpoint_url=settings.s3_endpoint,
region_name=settings.s3_region
)
# --- 数据模型 ---
class Project(Base):
__tablename__ = "projects"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String, nullable=False)
# cascade="all, delete-orphan" 确保在 db.delete(project) 时自动删除关联的 Markdown 记录
markdowns = relationship("Markdown", back_populates="project", cascade="all, delete-orphan")
class Markdown(Base):
__tablename__ = "markdowns"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
title = Column(String, nullable=False)
s3_key = Column(String, nullable=False)
project_id = Column(String, ForeignKey("projects.id", ondelete="CASCADE"))
project = relationship("Project", back_populates="markdowns")
Base.metadata.create_all(bind=engine)
app = FastAPI()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# --- API 接口 ---
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/projects")
def create_project(name: str, db: Session = Depends(get_db)):
project = Project(name=name)
db.add(project)
db.commit()
db.refresh(project)
return project
@app.post("/projects/{project_id}/markdowns")
def upload_markdown(project_id: str, title: str, content: str, db: Session = Depends(get_db)):
project = db.query(Project).filter(Project.id == project_id).first()
if not project:
raise HTTPException(status_code=404, detail="Project not found")
# 1. 存入 S3
s3_key = f"projects/{project_id}/{uuid.uuid4()}.md"
s3_client.put_object(
Bucket=settings.s3_bucket_name,
Key=s3_key,
Body=content,
ContentType="text/markdown"
)
# 2. 存入数据库
md_record = Markdown(title=title, s3_key=s3_key, project_id=project_id)
db.add(md_record)
db.commit()
return {"id": md_record.id, "s3_key": s3_key}
@app.delete("/projects/{project_id}")
def delete_project(project_id: str, db: Session = Depends(get_db)):
project = db.query(Project).filter(Project.id == project_id).first()
if not project:
raise HTTPException(status_code=404, detail="Project not found")
# 1. 清理 S3 中的文件
markdowns = db.query(Markdown).filter(Markdown.project_id == project_id).all()
if markdowns:
keys = [{'Key': md.s3_key} for md in markdowns]
s3_client.delete_objects(
Bucket=settings.s3_bucket_name,
Delete={'Objects': keys}
)
# 2. 从数据库删除项目 (SQLAlchemy 会自动处理 markdowns 表的级联删除)
db.delete(project)
db.commit()
return {"message": f"Project {project_id} and its files have been purged."}