from fastapi import APIRouter, HTTPException from pydantic import BaseModel import hashlib import os from app.core.database import get_connection router = APIRouter(prefix="/api/users", tags=["users"]) class LoginRequest(BaseModel): username: str password: str class ChangePasswordRequest(BaseModel): username: str current_password: str new_password: str class LoginResponse(BaseModel): id: int username: str full_name: str | None email: str | None message: str def hash_password(password: str) -> str: """パスワードをハッシュ化""" # 実運用ではより安全なハッシュアルゴリズムを使用してください return hashlib.sha256(password.encode()).hexdigest() @router.post("/login", response_model=LoginResponse) async def login(request: LoginRequest): """ユーザーのログイン処理""" try: conn = get_connection() cur = conn.cursor() # ユーザーが存在するか確認 cur.execute( "SELECT id, username, password, full_name, email FROM users WHERE username = %s AND is_active = TRUE", (request.username,) ) user = cur.fetchone() cur.close() conn.close() if not user: raise HTTPException(status_code=401, detail="ユーザー名またはパスワードが正しくありません") # パスワードの検証 hashed_password = hash_password(request.password) if user["password"] != hashed_password: raise HTTPException(status_code=401, detail="ユーザー名またはパスワードが正しくありません") return LoginResponse( id=user["id"], username=user["username"], full_name=user["full_name"], email=user["email"], message="ログインに成功しました" ) except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=f"ログイン処理エラー: {str(e)}") @router.post("/register") async def register(request: LoginRequest): """新規ユーザー登録(無効化済み)""" raise HTTPException(status_code=403, detail="新規ユーザー登録は現在受け付けていません") @router.post("/change-password") async def change_password(request: ChangePasswordRequest): """パスワード変更""" if len(request.new_password) < 8: raise HTTPException(status_code=400, detail="新しいパスワードは8文字以上である必要があります") try: conn = get_connection() cur = conn.cursor() cur.execute( "SELECT id, password FROM users WHERE username = %s AND is_active = TRUE", (request.username,) ) user = cur.fetchone() if not user: cur.close() conn.close() raise HTTPException(status_code=401, detail="ユーザーが見つかりません") if user["password"] != hash_password(request.current_password): cur.close() conn.close() raise HTTPException(status_code=401, detail="現在のパスワードが正しくありません") new_hashed = hash_password(request.new_password) cur.execute( "UPDATE users SET password = %s WHERE username = %s", (new_hashed, request.username) ) conn.commit() cur.close() conn.close() return {"message": "パスワードを変更しました"} except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=f"パスワード変更エラー: {str(e)}")