feat: add user preferences migration and context
This commit is contained in:
@@ -14,8 +14,8 @@ from core.security import (
|
||||
decode_access_token
|
||||
)
|
||||
from db.database import get_db
|
||||
from db.crud import get_user_by_username, get_user_by_email, create_user, change_user_password, update_user_aliyun_key
|
||||
from schemas.user import User, UserCreate, Token, PasswordChange, AliyunKeyUpdate, AliyunKeyVerifyResponse
|
||||
from db.crud import get_user_by_username, get_user_by_email, create_user, change_user_password, update_user_aliyun_key, get_user_preferences, update_user_preferences
|
||||
from schemas.user import User, UserCreate, Token, PasswordChange, AliyunKeyUpdate, AliyunKeyVerifyResponse, UserPreferences, UserPreferencesResponse
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["authentication"])
|
||||
|
||||
@@ -174,6 +174,32 @@ async def set_aliyun_key(
|
||||
|
||||
return user
|
||||
|
||||
@router.delete("/aliyun-key")
|
||||
@limiter.limit("5/minute")
|
||||
async def delete_aliyun_key(
|
||||
request: Request,
|
||||
current_user: Annotated[User, Depends(get_current_user)],
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
user = update_user_aliyun_key(
|
||||
db,
|
||||
user_id=current_user.id,
|
||||
encrypted_api_key=None
|
||||
)
|
||||
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found"
|
||||
)
|
||||
|
||||
prefs = get_user_preferences(db, current_user.id)
|
||||
if prefs.get("default_backend") == "aliyun":
|
||||
prefs["default_backend"] = "local"
|
||||
update_user_preferences(db, current_user.id, prefs)
|
||||
|
||||
return {"message": "Aliyun API key deleted", "preferences_updated": True}
|
||||
|
||||
@router.get("/aliyun-key/verify", response_model=AliyunKeyVerifyResponse)
|
||||
@limiter.limit("10/minute")
|
||||
async def verify_aliyun_key(
|
||||
@@ -211,3 +237,29 @@ async def verify_aliyun_key(
|
||||
valid=False,
|
||||
message="Aliyun API key is not working. Please check your API key."
|
||||
)
|
||||
|
||||
@router.get("/preferences", response_model=UserPreferencesResponse)
|
||||
@limiter.limit("30/minute")
|
||||
async def get_preferences(
|
||||
request: Request,
|
||||
current_user: Annotated[User, Depends(get_current_user)],
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
prefs = get_user_preferences(db, current_user.id)
|
||||
return UserPreferencesResponse(**prefs)
|
||||
|
||||
@router.put("/preferences")
|
||||
@limiter.limit("10/minute")
|
||||
async def update_preferences(
|
||||
request: Request,
|
||||
preferences: UserPreferences,
|
||||
current_user: Annotated[User, Depends(get_current_user)],
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
user = update_user_preferences(db, current_user.id, preferences.dict())
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="User not found"
|
||||
)
|
||||
return {"message": "Preferences updated"}
|
||||
|
||||
@@ -106,7 +106,7 @@ def change_user_password(
|
||||
def update_user_aliyun_key(
|
||||
db: Session,
|
||||
user_id: int,
|
||||
encrypted_api_key: str
|
||||
encrypted_api_key: Optional[str]
|
||||
) -> Optional[User]:
|
||||
user = get_user_by_id(db, user_id)
|
||||
if not user:
|
||||
@@ -229,3 +229,19 @@ def delete_cache_entry(db: Session, cache_id: int, user_id: int) -> bool:
|
||||
db.delete(cache)
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
def get_user_preferences(db: Session, user_id: int) -> dict:
|
||||
user = get_user_by_id(db, user_id)
|
||||
if not user or not user.user_preferences:
|
||||
return {"default_backend": "local", "onboarding_completed": False}
|
||||
return user.user_preferences
|
||||
|
||||
def update_user_preferences(db: Session, user_id: int, preferences: dict) -> Optional[User]:
|
||||
user = get_user_by_id(db, user_id)
|
||||
if not user:
|
||||
return None
|
||||
user.user_preferences = preferences
|
||||
user.updated_at = datetime.utcnow()
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
return user
|
||||
|
||||
@@ -21,6 +21,7 @@ class User(Base):
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
is_superuser = Column(Boolean, default=False, nullable=False)
|
||||
aliyun_api_key = Column(Text, nullable=True)
|
||||
user_preferences = Column(JSON, nullable=True, default=lambda: {"default_backend": "local", "onboarding_completed": False})
|
||||
created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
|
||||
|
||||
|
||||
37
qwen3-tts-backend/migrate_user_preferences.py
Normal file
37
qwen3-tts-backend/migrate_user_preferences.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import sqlite3
|
||||
import json
|
||||
import os
|
||||
|
||||
DB_PATH = os.path.join(os.path.dirname(__file__), "qwen_tts.db")
|
||||
|
||||
def migrate():
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
cursor.execute("SELECT user_preferences FROM users LIMIT 1")
|
||||
print("Column user_preferences already exists, skipping migration")
|
||||
except sqlite3.OperationalError:
|
||||
print("Adding user_preferences column to users table...")
|
||||
cursor.execute("""
|
||||
ALTER TABLE users
|
||||
ADD COLUMN user_preferences TEXT DEFAULT NULL
|
||||
""")
|
||||
|
||||
cursor.execute("SELECT id FROM users")
|
||||
user_ids = cursor.fetchall()
|
||||
|
||||
default_prefs = json.dumps({"default_backend": "local", "onboarding_completed": False})
|
||||
for (user_id,) in user_ids:
|
||||
cursor.execute(
|
||||
"UPDATE users SET user_preferences = ? WHERE id = ?",
|
||||
(default_prefs, user_id)
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
print(f"Migration completed: Added user_preferences column and initialized {len(user_ids)} users")
|
||||
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
migrate()
|
||||
@@ -118,3 +118,11 @@ class AliyunKeyUpdate(BaseModel):
|
||||
class AliyunKeyVerifyResponse(BaseModel):
|
||||
valid: bool
|
||||
message: str
|
||||
|
||||
class UserPreferences(BaseModel):
|
||||
default_backend: str = Field(default="local", pattern="^(local|aliyun)$")
|
||||
onboarding_completed: bool = Field(default=False)
|
||||
|
||||
class UserPreferencesResponse(BaseModel):
|
||||
default_backend: str
|
||||
onboarding_completed: bool
|
||||
|
||||
Reference in New Issue
Block a user