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 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): """新規ユーザー登録""" try: if len(request.password) < 6: raise HTTPException(status_code=400, detail="パスワードは6文字以上である必要があります") conn = get_connection() cur = conn.cursor() # ユーザーが既に存在するか確認 cur.execute("SELECT id FROM users WHERE username = %s", (request.username,)) if cur.fetchone(): cur.close() conn.close() raise HTTPException(status_code=400, detail="このユーザー名は既に使用されています") # ユーザーを登録 hashed_password = hash_password(request.password) cur.execute( "INSERT INTO users (username, password) VALUES (%s, %s) RETURNING id, username", (request.username, hashed_password) ) new_user = cur.fetchone() conn.commit() cur.close() conn.close() return { "id": new_user["id"], "username": new_user["username"], "message": "ユーザー登録が完了しました" } except HTTPException: raise except Exception as e: raise HTTPException(status_code=500, detail=f"登録処理エラー: {str(e)}")