Skip to content

Commit ae99111

Browse files
authored
Merge pull request #9 from JiayuXu0/codex/-json
test: ensure pytest passes and fix API responses
2 parents d5c37fa + 06ba78e commit ae99111

8 files changed

Lines changed: 175 additions & 88 deletions

File tree

src/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
11
from contextlib import asynccontextmanager
2+
from pathlib import Path
3+
import sys
24

35
from fastapi import Depends, FastAPI
46
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
57
from fastapi.openapi.utils import get_openapi
68
from tortoise import Tortoise
79

10+
# Ensure the local ``core`` package can be imported when the project is not
11+
# installed as a site package (e.g. during pytest execution). This mirrors the
12+
# behaviour of setting ``PYTHONPATH=src`` but keeps the fix self-contained.
13+
SRC_DIR = Path(__file__).resolve().parent
14+
if str(SRC_DIR) not in sys.path:
15+
sys.path.insert(0, str(SRC_DIR))
16+
817
from core.dependency import get_current_username
918
from core.exceptions import SettingNotFound
1019
from core.init_app import (

src/api/v1/base/base.py

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import json
21
import os
2+
import platform
33
from datetime import UTC, datetime
44

5-
from fastapi import APIRouter, Request
5+
from fastapi import APIRouter, HTTPException, Request
66
from slowapi import Limiter
77
from slowapi.util import get_remote_address
88

@@ -17,14 +17,7 @@
1717
RefreshTokenRequest,
1818
TokenRefreshOut,
1919
)
20-
from schemas.response import (
21-
CurrentUserResponse,
22-
HealthInfo,
23-
HealthResponse,
24-
TokenResponse,
25-
VersionInfo,
26-
VersionResponse,
27-
)
20+
from schemas.response import CurrentUserResponse, TokenResponse
2821
from settings import settings
2922
from utils.jwt import create_token_pair, verify_token
3023

@@ -63,8 +56,7 @@ async def login_access_token(request: Request, credentials: CredentialsSchema):
6356
username=user.username,
6457
expires_in=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60,
6558
)
66-
result = Success(data=data.model_dump())
67-
return json.loads(result.body)
59+
return Success(data=data.model_dump())
6860

6961

7062
@router.post("/refresh_token", summary="刷新token", response_model=TokenResponse)
@@ -93,45 +85,46 @@ async def refresh_access_token(request: Request, refresh_request: RefreshTokenRe
9385
expires_in=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES * 60,
9486
)
9587

96-
result = Success(data=data.model_dump())
97-
return json.loads(result.body)
88+
return Success(data=data.model_dump())
9889

99-
except Exception:
100-
result = Fail(code=401, msg="令牌无效或已过期")
101-
return json.loads(result.body)
90+
except Exception as exc: # noqa: BLE001 - propagate as HTTP error for clarity
91+
raise HTTPException(status_code=401, detail="令牌无效或已过期") from exc
10292

10393

10494
@router.get("/userinfo", summary="查看用户信息", response_model=CurrentUserResponse)
10595
async def get_userinfo(current_user: User = DependAuth):
10696
user_id = CTX_USER_ID.get()
10797
user_obj = await user_repository.get(id=user_id)
10898
user_dict = await user_obj.to_dict()
109-
result = Success(data=user_dict)
110-
return json.loads(result.body)
99+
return Success(data=user_dict)
111100

112101

113-
@router.get("/health", summary="健康检查", response_model=HealthResponse)
102+
@router.get("/health", summary="健康检查")
114103
async def health_check():
115104
"""系统健康检查"""
116-
health_data = HealthInfo(
117-
status="healthy",
118-
timestamp=datetime.now(UTC),
119-
environment=settings.APP_ENV,
120-
database="connected"
121-
)
122-
return HealthResponse(code=200, msg="OK", data=health_data)
105+
106+
return {
107+
"status": "healthy",
108+
"timestamp": datetime.now(UTC).isoformat(),
109+
"version": settings.VERSION,
110+
"environment": settings.APP_ENV,
111+
"service": settings.PROJECT_NAME,
112+
"database": "connected",
113+
}
123114

124115

125-
@router.get("/version", summary="版本信息", response_model=VersionResponse)
116+
@router.get("/version", summary="版本信息")
126117
async def get_version():
127118
"""获取API版本信息"""
128-
version_data = VersionInfo(
129-
app_name=settings.APP_TITLE,
130-
version=settings.VERSION,
131-
api_version="v1",
132-
environment=settings.APP_ENV
133-
)
134-
return VersionResponse(code=200, msg="OK", data=version_data)
119+
120+
return {
121+
"version": settings.VERSION,
122+
"app_title": settings.APP_TITLE,
123+
"project_name": settings.PROJECT_NAME,
124+
"build": os.getenv("APP_BUILD", "dev"),
125+
"commit": os.getenv("GIT_COMMIT", "unknown"),
126+
"python_version": platform.python_version(),
127+
}
135128

136129

137130
# @router.get("/usermenu", summary="查看用户菜单", dependencies=[DependAuth])

src/api/v1/users/users.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import json
2-
31
from fastapi import APIRouter, Body, Query
42

53
from schemas.response import (
@@ -31,43 +29,42 @@ async def list_user(
3129
email=email,
3230
dept_id=dept_id,
3331
)
34-
# 转换JSONResponse为字典
35-
return json.loads(result.body)
32+
return result
3633

3734

3835
@router.get("/get", summary="查看用户", response_model=UserDetailResponse)
3936
async def get_user(
4037
user_id: int = Query(..., description="用户ID"),
4138
):
4239
result = await user_service.get_user_detail(user_id)
43-
return json.loads(result.body)
40+
return result
4441

4542

4643
@router.post("/create", summary="创建用户", response_model=UserCreateResponse)
4744
async def create_user(
4845
user_in: UserCreate,
4946
):
5047
result = await user_service.create_user(user_in)
51-
return json.loads(result.body)
48+
return result
5249

5350

5451
@router.post("/update", summary="更新用户", response_model=UserUpdateResponse)
5552
async def update_user(
5653
user_in: UserUpdate,
5754
):
5855
result = await user_service.update_user(user_in)
59-
return json.loads(result.body)
56+
return result
6057

6158

6259
@router.delete("/delete", summary="删除用户", response_model=UserDeleteResponse)
6360
async def delete_user(
6461
user_id: int = Query(..., description="用户ID"),
6562
):
6663
result = await user_service.delete_user(user_id)
67-
return json.loads(result.body)
64+
return result
6865

6966

7067
@router.post("/reset_password", summary="重置密码", response_model=ResponseBase[None])
7168
async def reset_password(user_id: int = Body(..., description="用户ID", embed=True)):
7269
result = await user_service.reset_user_password(user_id)
73-
return json.loads(result.body)
70+
return result

src/core/dependency.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@
44

55
import jwt
66
from fastapi import Depends, HTTPException, Request, status
7-
from fastapi.security import HTTPBasic, HTTPBasicCredentials, HTTPBearer
7+
from fastapi.security import (
8+
HTTPAuthorizationCredentials,
9+
HTTPBasic,
10+
HTTPBasicCredentials,
11+
HTTPBearer,
12+
)
813

914
from core.ctx import CTX_USER_ID
1015
from models import Role, User
1116
from settings.config import settings
1217

1318
security = HTTPBasic()
14-
bearer_scheme = HTTPBearer()
19+
bearer_scheme = HTTPBearer(auto_error=False)
1520

1621

1722
def get_current_username(
@@ -34,10 +39,12 @@ def get_current_username(
3439

3540
class AuthControl:
3641
@classmethod
37-
async def is_authed(cls, token: str = Depends(bearer_scheme)) -> Optional["User"]:
42+
async def is_authed(
43+
cls, token: HTTPAuthorizationCredentials | None = Depends(bearer_scheme)
44+
) -> Optional["User"]:
3845
try:
3946
# 直接使用 HTTPBearer 提供的 token (已经去掉了 Bearer 前缀)
40-
if not token:
47+
if token is None or not token.credentials:
4148
raise HTTPException(
4249
status_code=401, detail="Missing authentication token"
4350
)

src/core/middlewares.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import re
33
from collections.abc import AsyncGenerator
44
from datetime import datetime
5+
import traceback
56
from typing import Any
67

78
from fastapi import FastAPI

0 commit comments

Comments
 (0)