491 lines
14 KiB
Python
491 lines
14 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
重新创建完整的app目录结构和文件
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
def create_app_directory():
|
|
"""创建app目录结构"""
|
|
print("=== 创建app目录结构 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
# 创建主要目录结构
|
|
directories = [
|
|
'app',
|
|
'app/core',
|
|
'app/api',
|
|
'app/api/v1',
|
|
'app/api/v1/endpoints',
|
|
'app/models',
|
|
'app/schemas',
|
|
'app/services',
|
|
'app/utils'
|
|
]
|
|
|
|
for dir_path in directories:
|
|
full_path = base_dir / dir_path
|
|
full_path.mkdir(parents=True, exist_ok=True)
|
|
print(f"✓ 创建目录: {dir_path}")
|
|
|
|
def create_init_files():
|
|
"""创建__init__.py文件"""
|
|
print("\n=== 创建__init__.py文件 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
# 各目录的__init__.py内容
|
|
init_contents = {
|
|
'app/__init__.py': '"""云盘应用包"""\n\n__version__ = "1.0.0"\n',
|
|
'app/core/__init__.py': '"""核心模块包"""\n',
|
|
'app/api/__init__.py': '"""API模块包"""\n',
|
|
'app/api/v1/__init__.py': '"""API v1模块包"""\n',
|
|
'app/api/v1/endpoints/__init__.py': '"""API端点模块包"""\n',
|
|
'app/models/__init__.py': '"""数据模型包"""\n',
|
|
'app/schemas/__init__.py': '"""Pydantic模式包"""\n',
|
|
'app/services/__init__.py': '"""业务逻辑服务包"""\n',
|
|
'app/utils/__init__.py': '"""工具函数包"""\n'
|
|
}
|
|
|
|
for file_path, content in init_contents.items():
|
|
full_path = base_dir / file_path
|
|
if not full_path.exists():
|
|
full_path.write_text(content, encoding='utf-8')
|
|
print(f"✓ 创建文件: {file_path}")
|
|
|
|
def create_core_files():
|
|
"""创建核心文件"""
|
|
print("\n=== 创建核心文件 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
# app/core/config.py
|
|
config_content = '''from pydantic_settings import BaseSettings
|
|
from typing import List
|
|
import os
|
|
|
|
class Settings(BaseSettings):
|
|
# 基础配置
|
|
ENVIRONMENT: str = "development"
|
|
DEBUG: bool = True
|
|
|
|
# 数据库配置
|
|
DATABASE_URL: str = "mysql+pymysql://mytest_db:mytest_db@101.126.85.76:3306/mytest_db"
|
|
|
|
# Redis配置
|
|
REDIS_URL: str = "redis://localhost:6379"
|
|
|
|
# JWT配置
|
|
JWT_SECRET_KEY: str = "your-super-secret-jwt-key-change-in-production"
|
|
JWT_ALGORITHM: str = "HS256"
|
|
JWT_EXPIRE_MINUTES: int = 30
|
|
JWT_REFRESH_EXPIRE_DAYS: int = 7
|
|
|
|
# CORS配置
|
|
ALLOWED_HOSTS: List[str] = [
|
|
"http://localhost:3000",
|
|
"http://localhost:3001",
|
|
"http://localhost:3002",
|
|
"http://localhost:3003",
|
|
"http://localhost:3004",
|
|
"http://127.0.0.1:3000",
|
|
"http://127.0.0.1:3001",
|
|
"http://127.0.0.1:3002",
|
|
"http://127.0.0.1:3003",
|
|
"http://127.0.0.1:3004",
|
|
"http://172.16.16.89:3000",
|
|
"http://172.16.16.89:3001",
|
|
"http://172.16.16.89:3002",
|
|
"http://172.16.16.89:3003",
|
|
"http://172.16.16.89:3004",
|
|
"*"
|
|
]
|
|
|
|
# 文件上传配置
|
|
MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 10MB
|
|
UPLOAD_DIR: str = "uploads"
|
|
ALLOWED_EXTENSIONS: List[str] = [
|
|
# 图片
|
|
".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg",
|
|
# 文档
|
|
".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
|
|
".txt", ".rtf", ".csv",
|
|
# 压缩文件
|
|
".zip", ".rar", ".7z", ".tar", ".gz",
|
|
# 音频
|
|
".mp3", ".wav", ".flac", ".aac", ".ogg",
|
|
# 视频
|
|
".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv",
|
|
# 代码文件
|
|
".py", ".js", ".html", ".css", ".json", ".xml", ".yaml", ".yml",
|
|
".java", ".cpp", ".c", ".h", ".cs", ".php", ".rb", ".go",
|
|
".sql", ".sh", ".bat", ".ps1", ".md", ".log"
|
|
]
|
|
|
|
# 安全配置
|
|
BCRYPT_ROUNDS: int = 12
|
|
|
|
class Config:
|
|
env_file = ".env"
|
|
case_sensitive = True
|
|
|
|
settings = Settings()
|
|
'''
|
|
|
|
config_file = base_dir / 'app' / 'core' / 'config.py'
|
|
config_file.write_text(config_content, encoding='utf-8')
|
|
print("✓ 创建 app/core/config.py")
|
|
|
|
# app/core/database.py
|
|
database_content = '''from sqlalchemy import create_engine
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy.orm import sessionmaker
|
|
from app.core.config import settings
|
|
|
|
# 创建数据库引擎
|
|
engine = create_engine(
|
|
settings.DATABASE_URL,
|
|
pool_pre_ping=True,
|
|
pool_recycle=300,
|
|
)
|
|
|
|
# 创建会话工厂
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
|
# 创建Base类
|
|
Base = declarative_base()
|
|
|
|
def get_db():
|
|
"""获取数据库会话"""
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
'''
|
|
|
|
database_file = base_dir / 'app' / 'core' / 'database.py'
|
|
database_file.write_text(database_content, encoding='utf-8')
|
|
print("✓ 创建 app/core/database.py")
|
|
|
|
# app/core/security.py
|
|
security_content = '''from datetime import datetime, timedelta
|
|
from typing import Optional
|
|
from jose import JWTError, jwt
|
|
from passlib.context import CryptContext
|
|
from app.core.config import settings
|
|
|
|
# 密码加密上下文
|
|
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
|
|
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|
"""验证密码"""
|
|
return pwd_context.verify(plain_password, hashed_password)
|
|
|
|
def get_password_hash(password: str) -> str:
|
|
"""获取密码哈希"""
|
|
return pwd_context.hash(password)
|
|
|
|
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
|
|
"""创建访问令牌"""
|
|
to_encode = data.copy()
|
|
if expires_delta:
|
|
expire = datetime.utcnow() + expires_delta
|
|
else:
|
|
expire = datetime.utcnow() + timedelta(minutes=settings.JWT_EXPIRE_MINUTES)
|
|
|
|
to_encode.update({"exp": expire})
|
|
encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
|
|
return encoded_jwt
|
|
|
|
def verify_token(token: str):
|
|
"""验证令牌"""
|
|
try:
|
|
payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[settings.JWT_ALGORITHM])
|
|
return payload
|
|
except JWTError:
|
|
return None
|
|
'''
|
|
|
|
security_file = base_dir / 'app' / 'core' / 'security.py'
|
|
security_file.write_text(security_content, encoding='utf-8')
|
|
print("✓ 创建 app/core/security.py")
|
|
|
|
def create_api_files():
|
|
"""创建API文件"""
|
|
print("\n=== 创建API文件 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
# app/api/v1/endpoints/health.py
|
|
health_content = '''from fastapi import APIRouter, status
|
|
from datetime import datetime
|
|
|
|
router = APIRouter()
|
|
|
|
@router.get("/health", status_code=status.HTTP_200_OK)
|
|
async def health_check():
|
|
"""健康检查端点"""
|
|
return {
|
|
"status": "healthy",
|
|
"timestamp": datetime.utcnow(),
|
|
"version": "1.0.0",
|
|
"message": "云盘后端服务运行正常"
|
|
}
|
|
|
|
@router.get("/")
|
|
async def root():
|
|
"""根端点"""
|
|
return {
|
|
"message": "云盘应用 API",
|
|
"version": "1.0.0",
|
|
"docs": "/docs",
|
|
"health": "/api/v1/health"
|
|
}
|
|
'''
|
|
|
|
health_file = base_dir / 'app' / 'api' / 'v1' / 'endpoints' / 'health.py'
|
|
health_file.write_text(health_content, encoding='utf-8')
|
|
print("✓ 创建 app/api/v1/endpoints/health.py")
|
|
|
|
# app/api/v1/endpoints/auth.py
|
|
auth_content = '''from fastapi import APIRouter, Depends, HTTPException, status
|
|
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
|
from sqlalchemy.orm import Session
|
|
from typing import Optional
|
|
from datetime import timedelta
|
|
|
|
from app.core.database import get_db
|
|
from app.core.security import verify_password, create_access_token
|
|
from app.core.config import settings
|
|
from app.schemas.user import UserCreate, UserResponse, Token
|
|
|
|
router = APIRouter()
|
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/auth/token")
|
|
|
|
@router.post("/register", response_model=UserResponse)
|
|
async def register(user_data: UserCreate, db: Session = Depends(get_db)):
|
|
"""用户注册"""
|
|
# TODO: 实现用户注册逻辑
|
|
return {"message": "注册功能待实现"}
|
|
|
|
@router.post("/token", response_model=Token)
|
|
async def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
|
|
"""用户登录"""
|
|
# TODO: 实现用户登录逻辑
|
|
return {
|
|
"access_token": "dummy_token",
|
|
"token_type": "bearer",
|
|
"expires_in": settings.JWT_EXPIRE_MINUTES * 60
|
|
}
|
|
|
|
@router.get("/me", response_model=UserResponse)
|
|
async def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
|
|
"""获取当前用户信息"""
|
|
# TODO: 实现获取当前用户逻辑
|
|
return {"message": "用户信息功能待实现"}
|
|
'''
|
|
|
|
auth_file = base_dir / 'app' / 'api' / 'v1' / 'endpoints' / 'auth.py'
|
|
auth_file.write_text(auth_content, encoding='utf-8')
|
|
print("✓ 创建 app/api/v1/endpoints/auth.py")
|
|
|
|
# app/api/v1/endpoints/files.py
|
|
files_content = '''from fastapi import APIRouter, Depends, HTTPException, UploadFile, File
|
|
from sqlalchemy.orm import Session
|
|
from typing import List
|
|
|
|
from app.core.database import get_db
|
|
from app.schemas.file import FileResponse, FileUploadResponse
|
|
|
|
router = APIRouter()
|
|
|
|
@router.post("/upload", response_model=FileUploadResponse)
|
|
async def upload_file(
|
|
file: UploadFile = File(...),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""上传文件"""
|
|
# TODO: 实现文件上传逻辑
|
|
return {
|
|
"message": "文件上传功能待实现",
|
|
"filename": file.filename,
|
|
"size": 0
|
|
}
|
|
|
|
@router.get("/list", response_model=List[FileResponse])
|
|
async def list_files(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取文件列表"""
|
|
# TODO: 实现文件列表逻辑
|
|
return []
|
|
|
|
@router.get("/{file_id}", response_model=FileResponse)
|
|
async def get_file_info(file_id: int, db: Session = Depends(get_db)):
|
|
"""获取文件信息"""
|
|
# TODO: 实现获取文件信息逻辑
|
|
return {"message": "文件信息功能待实现"}
|
|
|
|
@router.delete("/{file_id}")
|
|
async def delete_file(file_id: int, db: Session = Depends(get_db)):
|
|
"""删除文件"""
|
|
# TODO: 实现文件删除逻辑
|
|
return {"message": "文件删除功能待实现"}
|
|
'''
|
|
|
|
files_file = base_dir / 'app' / 'api' / 'v1' / 'endpoints' / 'files.py'
|
|
files_file.write_text(files_content, encoding='utf-8')
|
|
print("✓ 创建 app/api/v1/endpoints/files.py")
|
|
|
|
def create_schema_files():
|
|
"""创建Pydantic模式文件"""
|
|
print("\n=== 创建模式文件 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
# app/schemas/user.py
|
|
user_schema_content = '''from pydantic import BaseModel, EmailStr
|
|
from typing import Optional
|
|
|
|
class UserBase(BaseModel):
|
|
username: str
|
|
email: EmailStr
|
|
|
|
class UserCreate(UserBase):
|
|
password: str
|
|
confirm_password: str
|
|
|
|
class UserUpdate(BaseModel):
|
|
username: Optional[str] = None
|
|
email: Optional[EmailStr] = None
|
|
|
|
class UserResponse(UserBase):
|
|
id: int
|
|
is_active: bool
|
|
created_at: str
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class Token(BaseModel):
|
|
access_token: str
|
|
token_type: str
|
|
expires_in: int
|
|
'''
|
|
|
|
user_schema_file = base_dir / 'app' / 'schemas' / 'user.py'
|
|
user_schema_file.write_text(user_schema_content, encoding='utf-8')
|
|
print("✓ 创建 app/schemas/user.py")
|
|
|
|
# app/schemas/file.py
|
|
file_schema_content = '''from pydantic import BaseModel
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
|
|
class FileBase(BaseModel):
|
|
filename: str
|
|
original_filename: str
|
|
file_size: int
|
|
content_type: str
|
|
|
|
class FileCreate(FileBase):
|
|
pass
|
|
|
|
class FileUpdate(BaseModel):
|
|
filename: Optional[str] = None
|
|
|
|
class FileResponse(FileBase):
|
|
id: int
|
|
user_id: int
|
|
file_path: str
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
class FileUploadResponse(BaseModel):
|
|
message: str
|
|
filename: str
|
|
size: int
|
|
file_id: Optional[int] = None
|
|
'''
|
|
|
|
file_schema_file = base_dir / 'app' / 'schemas' / 'file.py'
|
|
file_schema_file.write_text(file_schema_content, encoding='utf-8')
|
|
print("✓ 创建 app/schemas/file.py")
|
|
|
|
def verify_structure():
|
|
"""验证项目结构"""
|
|
print("\n=== 验证项目结构 ===")
|
|
|
|
base_dir = Path('.')
|
|
|
|
required_files = [
|
|
'app/__init__.py',
|
|
'app/core/__init__.py',
|
|
'app/core/config.py',
|
|
'app/core/database.py',
|
|
'app/core/security.py',
|
|
'app/api/__init__.py',
|
|
'app/api/v1/__init__.py',
|
|
'app/api/v1/endpoints/__init__.py',
|
|
'app/api/v1/endpoints/health.py',
|
|
'app/api/v1/endpoints/auth.py',
|
|
'app/api/v1/endpoints/files.py',
|
|
'app/schemas/__init__.py',
|
|
'app/schemas/user.py',
|
|
'app/schemas/file.py'
|
|
]
|
|
|
|
all_exist = True
|
|
for file_path in required_files:
|
|
full_path = base_dir / file_path
|
|
if full_path.exists():
|
|
print(f"✓ {file_path}")
|
|
else:
|
|
print(f"✗ {file_path}")
|
|
all_exist = False
|
|
|
|
if all_exist:
|
|
print("\n🎉 所有文件创建成功!")
|
|
print("现在可以运行: python main.py")
|
|
else:
|
|
print("\n⚠️ 部分文件创建失败,请检查错误信息")
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("=== 重新创建app目录结构 ===")
|
|
|
|
# 创建目录结构
|
|
create_app_directory()
|
|
|
|
# 创建__init__.py文件
|
|
create_init_files()
|
|
|
|
# 创建核心文件
|
|
create_core_files()
|
|
|
|
# 创建API文件
|
|
create_api_files()
|
|
|
|
# 创建模式文件
|
|
create_schema_files()
|
|
|
|
# 验证结构
|
|
verify_structure()
|
|
|
|
print("\n=== 恢复完成 ===")
|
|
print("app目录结构和所有必要文件已重新创建")
|
|
print("下一步:")
|
|
print("1. 激活虚拟环境: source venv/bin/activate")
|
|
print("2. 安装依赖: pip install -r requirements.txt")
|
|
print("3. 启动服务: python main.py")
|
|
|
|
if __name__ == '__main__':
|
|
main() |