feat(api): 添加测试,小修小补
- **未经测试**
This commit is contained in:
@@ -13,10 +13,11 @@ RUN apt-get update && apt-get install -y \
|
||||
# 复制依赖文件
|
||||
COPY uv.lock .
|
||||
COPY pyproject.toml .
|
||||
COPY requirements.txt .
|
||||
|
||||
# 安装Python依赖
|
||||
RUN uv sync --locked
|
||||
RUN pip install uvicorn
|
||||
RUN uv sync
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
# 复制应用代码
|
||||
COPY . .
|
||||
|
||||
@@ -10,9 +10,9 @@ load_dotenv()
|
||||
class Settings:
|
||||
# 数据库设置
|
||||
DATABASE_URL: str = os.getenv(
|
||||
"DATABASE_URL", "mysql+aiomysql://root:password@localhost:3306/osu_api"
|
||||
"DATABASE_URL", "mysql+aiomysql://root:password@127.0.0.1:3306/osu_api"
|
||||
)
|
||||
REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379/0")
|
||||
REDIS_URL: str = os.getenv("REDIS_URL", "redis://127.0.0.1:6379/0")
|
||||
|
||||
# JWT 设置
|
||||
SECRET_KEY: str = os.getenv("SECRET_KEY", "your-secret-key-here")
|
||||
|
||||
@@ -87,7 +87,7 @@ class BeatmapsetBase(SQLModel):
|
||||
# Beatmapset
|
||||
artist: str = Field(index=True)
|
||||
artist_unicode: str = Field(index=True)
|
||||
covers: BeatmapCovers = Field(sa_column=Column(JSON))
|
||||
covers: BeatmapCovers | None = Field(sa_column=Column(JSON))
|
||||
creator: str
|
||||
favourite_count: int
|
||||
nsfw: bool = Field(default=False)
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import JSON, Column, DateTime
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
from sqlalchemy.orm import Mapped
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .user import User
|
||||
@@ -70,7 +71,7 @@ class LegacyUserStatistics(SQLModel, table=True):
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
user: "User" = Relationship(back_populates="statistics")
|
||||
user: Mapped["User"] = Relationship(back_populates="statistics")
|
||||
|
||||
|
||||
class LegacyOAuthToken(SQLModel, table=True):
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import datetime
|
||||
import math
|
||||
from typing import Literal, TYPE_CHECKING, List
|
||||
|
||||
from app.models.score import Rank, APIMod, GameMode
|
||||
from app.models.score import Rank, APIMod, GameMode, MODE_TO_INT
|
||||
|
||||
from .beatmap import Beatmap, BeatmapResp
|
||||
from .beatmapset import Beatmapset, BeatmapsetResp
|
||||
@@ -84,6 +84,7 @@ class ScoreResp(ScoreBase):
|
||||
legacy_total_score: int = 0 # FIXME
|
||||
processed: bool = False # solo_score
|
||||
weight: float = 0.0
|
||||
ruleset_id: int | None
|
||||
beatmap: BeatmapResp | None = None
|
||||
beatmapset: BeatmapsetResp | None = None
|
||||
# FIXME: user: APIUser | None = None
|
||||
@@ -96,6 +97,7 @@ class ScoreResp(ScoreBase):
|
||||
s.beatmapset = BeatmapsetResp.from_db(score.beatmap.beatmapset)
|
||||
s.is_perfect_combo = s.max_combo == s.beatmap.max_combo
|
||||
s.legacy_perfect = s.max_combo == s.beatmap.max_combo
|
||||
s.ruleset_id=MODE_TO_INT[score.ruleset_id]
|
||||
if score.best_id:
|
||||
# https://osu.ppy.sh/wiki/Performance_points/Weighting_system
|
||||
s.weight = math.pow(0.95, score.best_id)
|
||||
|
||||
@@ -3,6 +3,7 @@ from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import Column, DateTime
|
||||
from sqlalchemy.orm import Mapped
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -20,7 +21,7 @@ class Team(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
members: list["TeamMember"] = Relationship(back_populates="team")
|
||||
members: Mapped[list["TeamMember"]] = Relationship(back_populates="team")
|
||||
|
||||
|
||||
class TeamMember(SQLModel, table=True):
|
||||
@@ -33,5 +34,5 @@ class TeamMember(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="team_membership")
|
||||
team: "Team" = Relationship(back_populates="members")
|
||||
user: Mapped["User"] = Relationship(back_populates="team_membership")
|
||||
team: Mapped["Team"] = Relationship(back_populates="members")
|
||||
@@ -10,6 +10,7 @@ from .team import TeamMember
|
||||
|
||||
from sqlalchemy import DECIMAL, JSON, Column, Date, DateTime, Text
|
||||
from sqlalchemy.dialects.mysql import VARCHAR
|
||||
from sqlalchemy.orm import Mapped
|
||||
from sqlmodel import BigInteger, Field, Relationship, SQLModel
|
||||
|
||||
|
||||
@@ -69,31 +70,31 @@ class User(SQLModel, table=True):
|
||||
return datetime.fromtimestamp(latest_activity) if latest_activity > 0 else None
|
||||
|
||||
# 关联关系
|
||||
lazer_profile: Optional["LazerUserProfile"] = Relationship(back_populates="user")
|
||||
lazer_statistics: list["LazerUserStatistics"] = Relationship(back_populates="user")
|
||||
lazer_counts: Optional["LazerUserCounts"] = Relationship(back_populates="user")
|
||||
lazer_achievements: list["LazerUserAchievement"] = Relationship(
|
||||
lazer_profile: Mapped[Optional["LazerUserProfile"]] = Relationship(back_populates="user")
|
||||
lazer_statistics: Mapped[list["LazerUserStatistics"]] = Relationship(back_populates="user")
|
||||
lazer_counts: Mapped[Optional["LazerUserCounts"]] = Relationship(back_populates="user")
|
||||
lazer_achievements: Mapped[list["LazerUserAchievement"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
lazer_profile_sections: list["LazerUserProfileSections"] = Relationship(
|
||||
lazer_profile_sections: Mapped[list["LazerUserProfileSections"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
statistics: list[LegacyUserStatistics] = Relationship(back_populates="user")
|
||||
team_membership: list[TeamMember] = Relationship(back_populates="user")
|
||||
daily_challenge_stats: Optional["DailyChallengeStats"] = Relationship(
|
||||
statistics: list["LegacyUserStatistics"] = Relationship(back_populates="user")
|
||||
team_membership: Mapped[list["TeamMember"]] = Relationship(back_populates="user")
|
||||
daily_challenge_stats: Mapped[Optional["DailyChallengeStats"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
rank_history: list["RankHistory"] = Relationship(back_populates="user")
|
||||
avatar: Optional["UserAvatar"] = Relationship(back_populates="user")
|
||||
active_banners: list["LazerUserBanners"] = Relationship(back_populates="user")
|
||||
lazer_badges: list["LazerUserBadge"] = Relationship(back_populates="user")
|
||||
lazer_monthly_playcounts: list["LazerUserMonthlyPlaycounts"] = Relationship(
|
||||
rank_history: Mapped[list["RankHistory"]] = Relationship(back_populates="user")
|
||||
avatar: Mapped[Optional["UserAvatar"]] = Relationship(back_populates="user")
|
||||
active_banners: Mapped[list["LazerUserBanners"]] = Relationship(back_populates="user")
|
||||
lazer_badges: Mapped[list["LazerUserBadge"]] = Relationship(back_populates="user")
|
||||
lazer_monthly_playcounts: Mapped[list["LazerUserMonthlyPlaycounts"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
lazer_previous_usernames: list["LazerUserPreviousUsername"] = Relationship(
|
||||
lazer_previous_usernames: Mapped[list["LazerUserPreviousUsername"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
lazer_replays_watched: list["LazerUserReplaysWatched"] = Relationship(
|
||||
lazer_replays_watched: Mapped[list["LazerUserReplaysWatched"]] = Relationship(
|
||||
back_populates="user"
|
||||
)
|
||||
|
||||
@@ -154,7 +155,7 @@ class LazerUserProfile(SQLModel, table=True):
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
user: "User" = Relationship(back_populates="lazer_profile")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_profile")
|
||||
|
||||
|
||||
class LazerUserProfileSections(SQLModel, table=True):
|
||||
@@ -172,7 +173,7 @@ class LazerUserProfileSections(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_profile_sections")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_profile_sections")
|
||||
|
||||
|
||||
class LazerUserCountry(SQLModel, table=True):
|
||||
@@ -237,7 +238,7 @@ class LazerUserCounts(SQLModel, table=True):
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
user: "User" = Relationship(back_populates="lazer_counts")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_counts")
|
||||
|
||||
|
||||
class LazerUserStatistics(SQLModel, table=True):
|
||||
@@ -297,7 +298,7 @@ class LazerUserStatistics(SQLModel, table=True):
|
||||
)
|
||||
|
||||
# 关联关系
|
||||
user: "User" = Relationship(back_populates="lazer_statistics")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_statistics")
|
||||
|
||||
|
||||
class LazerUserBanners(SQLModel, table=True):
|
||||
@@ -310,7 +311,7 @@ class LazerUserBanners(SQLModel, table=True):
|
||||
is_active: bool | None = Field(default=None)
|
||||
|
||||
# 修正user关系的back_populates值
|
||||
user: "User" = Relationship(back_populates="active_banners")
|
||||
user: Mapped["User"] = Relationship(back_populates="active_banners")
|
||||
|
||||
|
||||
class LazerUserAchievement(SQLModel, table=True):
|
||||
@@ -323,7 +324,7 @@ class LazerUserAchievement(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_achievements")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_achievements")
|
||||
|
||||
|
||||
class LazerUserBadge(SQLModel, table=True):
|
||||
@@ -344,7 +345,7 @@ class LazerUserBadge(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_badges")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_badges")
|
||||
|
||||
|
||||
class LazerUserMonthlyPlaycounts(SQLModel, table=True):
|
||||
@@ -362,7 +363,7 @@ class LazerUserMonthlyPlaycounts(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_monthly_playcounts")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_monthly_playcounts")
|
||||
|
||||
|
||||
class LazerUserPreviousUsername(SQLModel, table=True):
|
||||
@@ -380,7 +381,7 @@ class LazerUserPreviousUsername(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_previous_usernames")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_previous_usernames")
|
||||
|
||||
|
||||
class LazerUserReplaysWatched(SQLModel, table=True):
|
||||
@@ -398,7 +399,7 @@ class LazerUserReplaysWatched(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="lazer_replays_watched")
|
||||
user: Mapped["User"] = Relationship(back_populates="lazer_replays_watched")
|
||||
|
||||
|
||||
# 类型转换用的 UserAchievement(不是 SQLAlchemy 模型)
|
||||
@@ -426,7 +427,7 @@ class DailyChallengeStats(SQLModel, table=True):
|
||||
weekly_streak_best: int = Field(default=0)
|
||||
weekly_streak_current: int = Field(default=0)
|
||||
|
||||
user: "User" = Relationship(back_populates="daily_challenge_stats")
|
||||
user: Mapped["User"] = Relationship(back_populates="daily_challenge_stats")
|
||||
|
||||
|
||||
class RankHistory(SQLModel, table=True):
|
||||
@@ -440,7 +441,7 @@ class RankHistory(SQLModel, table=True):
|
||||
default_factory=datetime.utcnow, sa_column=Column(DateTime)
|
||||
)
|
||||
|
||||
user: "User" = Relationship(back_populates="rank_history")
|
||||
user: Mapped["User"] = Relationship(back_populates="rank_history")
|
||||
|
||||
|
||||
class UserAvatar(SQLModel, table=True):
|
||||
@@ -458,4 +459,4 @@ class UserAvatar(SQLModel, table=True):
|
||||
r2_original_url: str | None = Field(default=None, max_length=500)
|
||||
r2_game_url: str | None = Field(default=None, max_length=500)
|
||||
|
||||
user: "User" = Relationship(back_populates="avatar")
|
||||
user: Mapped["User"] = Relationship(back_populates="avatar")
|
||||
|
||||
@@ -12,6 +12,11 @@ from app.auth import get_password_hash
|
||||
from app.database import (
|
||||
User,
|
||||
)
|
||||
from app.database.beatmapset import Beatmapset, BeatmapsetResp
|
||||
from app.database.beatmap import Beatmap, BeatmapResp
|
||||
from app.database.score import Score
|
||||
from app.models.score import GameMode, Rank, APIMod
|
||||
from app.models.beatmap import BeatmapRankStatus, Genre, Language
|
||||
from app.dependencies.database import create_tables, engine
|
||||
|
||||
from sqlmodel import select
|
||||
@@ -72,10 +77,138 @@ async def create_sample_user():
|
||||
return user
|
||||
|
||||
|
||||
async def create_sample_beatmap_data(user: User):
|
||||
"""创建示例谱面数据"""
|
||||
async with AsyncSession(engine) as session:
|
||||
async with session.begin():
|
||||
# 检查谱面集是否已存在
|
||||
statement = select(Beatmapset).where(Beatmapset.id == 1)
|
||||
result = await session.execute(statement)
|
||||
existing_beatmapset = result.scalars().first()
|
||||
if existing_beatmapset:
|
||||
print("示例谱面集已存在,跳过创建")
|
||||
return existing_beatmapset
|
||||
|
||||
# 创建谱面集
|
||||
beatmapset = Beatmapset(
|
||||
id=1,
|
||||
artist="Example Artist",
|
||||
artist_unicode="Example Artist",
|
||||
covers=None,
|
||||
creator="Googujiang",
|
||||
favourite_count=0,
|
||||
hype_current=0,
|
||||
hype_required=0,
|
||||
nsfw=False,
|
||||
play_count=0,
|
||||
preview_url="",
|
||||
source="",
|
||||
spotlight=False,
|
||||
title="Example Song",
|
||||
title_unicode="Example Song",
|
||||
user_id=user.id,
|
||||
video=False,
|
||||
availability_info=None,
|
||||
download_disabled=False,
|
||||
bpm=180.0,
|
||||
can_be_hyped=False,
|
||||
discussion_locked=False,
|
||||
last_updated=datetime.now(),
|
||||
ranked_date=datetime.now(),
|
||||
storyboard=False,
|
||||
submitted_date=datetime.now(),
|
||||
current_nominations=[],
|
||||
beatmap_status=BeatmapRankStatus.RANKED,
|
||||
beatmap_genre=Genre.ANY, # 使用整数表示Genre枚举
|
||||
beatmap_language=Language.ANY, # 使用整数表示Language枚举
|
||||
nominations_required=0,
|
||||
nominations_current=0,
|
||||
pack_tags=[],
|
||||
ratings=[],
|
||||
)
|
||||
session.add(beatmapset)
|
||||
await session.flush()
|
||||
|
||||
# 创建谱面
|
||||
beatmap = Beatmap(
|
||||
id=1,
|
||||
url="",
|
||||
mode=GameMode.OSU,
|
||||
beatmapset_id=1,
|
||||
difficulty_rating=5.5,
|
||||
beatmap_status=BeatmapRankStatus.RANKED,
|
||||
total_length=195,
|
||||
user_id=user.id,
|
||||
version="Example Difficulty",
|
||||
checksum="example_checksum",
|
||||
current_user_playcount=0,
|
||||
max_combo=1200,
|
||||
ar=9.0,
|
||||
cs=4.0,
|
||||
drain=5.0,
|
||||
accuracy=8.0,
|
||||
bpm=180.0,
|
||||
count_circles=1000,
|
||||
count_sliders=200,
|
||||
count_spinners=1,
|
||||
deleted_at=None,
|
||||
hit_length=180,
|
||||
last_updated=datetime.now(),
|
||||
passcount=10,
|
||||
playcount=50,
|
||||
)
|
||||
session.add(beatmap)
|
||||
await session.flush()
|
||||
|
||||
# 创建成绩
|
||||
score = Score(
|
||||
id=1,
|
||||
accuracy=0.9876,
|
||||
map_md5="example_checksum",
|
||||
best_id=1,
|
||||
build_id=None,
|
||||
classic_total_score=1234567,
|
||||
ended_at=datetime.now(),
|
||||
has_replay=True,
|
||||
max_combo=1100,
|
||||
mods=[APIMod(acronym="HD"), APIMod(acronym="DT")],
|
||||
passed=True,
|
||||
playlist_item_id=None,
|
||||
pp=250.5,
|
||||
preserve=True,
|
||||
rank=Rank.S,
|
||||
room_id=None,
|
||||
ruleset_id=GameMode.OSU,
|
||||
started_at=datetime.now(),
|
||||
total_score=1234567,
|
||||
type="solo_score",
|
||||
position=None,
|
||||
beatmap_id=1,
|
||||
user_id=user.id,
|
||||
n300=950,
|
||||
n100=30,
|
||||
n50=20,
|
||||
nmiss=5,
|
||||
ngeki=150,
|
||||
nkatu=50,
|
||||
nlarge_tick_miss=None,
|
||||
nslider_tail_hit=None,
|
||||
)
|
||||
session.add(score)
|
||||
await session.commit()
|
||||
await session.refresh(beatmapset)
|
||||
|
||||
print(f"成功创建示例谱面集: {beatmapset.title} (ID: {beatmapset.id})")
|
||||
print(f"成功创建示例谱面: {beatmap.version} (ID: {beatmap.id})")
|
||||
print(f"成功创建示例成绩: ID {score.id}")
|
||||
return beatmapset
|
||||
|
||||
|
||||
async def main():
|
||||
print("开始创建示例数据...")
|
||||
await create_tables()
|
||||
user = await create_sample_user()
|
||||
await create_sample_beatmap_data(user)
|
||||
print("示例数据创建完成!")
|
||||
print(f"用户名: {user.name}")
|
||||
print("密码: password123")
|
||||
@@ -83,4 +216,4 @@ async def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
asyncio.run(main())
|
||||
@@ -1,17 +1,54 @@
|
||||
fastapi~=0.116.1
|
||||
uvicorn[standard]==0.24.0
|
||||
sqlalchemy~=2.0.41
|
||||
alembic==1.12.1
|
||||
pymysql~=1.1.1
|
||||
cryptography==41.0.7
|
||||
redis~=6.2.0
|
||||
python-jose[cryptography]~=3.5.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
python-multipart==0.0.6
|
||||
pydantic[email]~=2.11.7
|
||||
python-dotenv~=1.1.1
|
||||
bcrypt~=4.3.0
|
||||
msgpack~=1.1.1
|
||||
sqlmodel~=0.0.24
|
||||
starlette~=0.47.2
|
||||
aiomysql==0.2.0
|
||||
alembic==1.16.4
|
||||
annotated-types==0.7.0
|
||||
anyio==4.9.0
|
||||
async-timeout==5.0.1
|
||||
bcrypt==4.3.0
|
||||
cffi==1.17.1
|
||||
cfgv==3.4.0
|
||||
click==8.2.1
|
||||
colorama==0.4.6
|
||||
cryptography==45.0.5
|
||||
distlib==0.4.0
|
||||
dnspython==2.7.0
|
||||
ecdsa==0.19.1
|
||||
email-validator==2.2.0
|
||||
fastapi==0.116.1
|
||||
filelock==3.18.0
|
||||
greenlet==3.2.3
|
||||
h11==0.16.0
|
||||
httptools==0.6.4
|
||||
identify==2.6.12
|
||||
idna==3.10
|
||||
mako==1.3.10
|
||||
markupsafe==3.0.2
|
||||
msgpack==1.1.1
|
||||
msgpack-types==0.5.0
|
||||
nodeenv==1.9.1
|
||||
passlib==1.7.4
|
||||
platformdirs==4.3.8
|
||||
pre-commit==4.2.0
|
||||
pyasn1==0.6.1
|
||||
pycparser==2.22
|
||||
pydantic==2.11.7
|
||||
pydantic-core==2.33.2
|
||||
pymysql==1.1.1
|
||||
python-dotenv==1.1.1
|
||||
python-jose==3.5.0
|
||||
python-multipart==0.0.20
|
||||
pyyaml==6.0.2
|
||||
redis==6.2.0
|
||||
rsa==4.9.1
|
||||
ruff==0.12.4
|
||||
six==1.17.0
|
||||
sniffio==1.3.1
|
||||
sqlalchemy==2.0.41
|
||||
sqlmodel==0.0.24
|
||||
starlette==0.47.2
|
||||
typing-extensions==4.14.1
|
||||
typing-inspection==0.4.1
|
||||
uvicorn==0.35.0
|
||||
uvloop==0.21.0
|
||||
virtualenv==20.32.0
|
||||
watchfiles==1.1.0
|
||||
websockets==15.0.1
|
||||
39
test_api.py
39
test_api.py
@@ -105,6 +105,25 @@ def get_current_user(access_token: str, ruleset: str = "osu"):
|
||||
return None
|
||||
|
||||
|
||||
def get_beatmap_scores(access_token: str, beatmap_id: int):
|
||||
"""获取谱面成绩数据"""
|
||||
url = f"{API_URL}/api/v2/beatmaps/{beatmap_id}/scores"
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=headers)
|
||||
if response.status_code == 200:
|
||||
print(f"✅ 成功获取谱面 {beatmap_id} 的成绩数据")
|
||||
return response.json()
|
||||
else:
|
||||
print(f"❌ 获取谱面成绩失败: {response.status_code}")
|
||||
print(f"响应内容: {response.text}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"❌ 获取谱面成绩请求失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
"""主测试函数"""
|
||||
print("=== osu! API 模拟服务器测试 ===\n")
|
||||
@@ -149,14 +168,26 @@ def main():
|
||||
print(f"游戏次数: {user_data['statistics']['play_count']}")
|
||||
print(f"命中精度: {user_data['statistics']['hit_accuracy']:.2f}%")
|
||||
|
||||
# 5. 测试令牌刷新
|
||||
print("\n5. 测试令牌刷新...")
|
||||
# 5. 测试获取谱面成绩
|
||||
print("\n5. 测试获取谱面成绩...")
|
||||
scores_data = get_beatmap_scores(token_data["access_token"], 1)
|
||||
if scores_data:
|
||||
print(f"谱面成绩总数: {len(scores_data['scores'])}")
|
||||
if scores_data['userScore']:
|
||||
print("用户在该谱面有成绩记录")
|
||||
print(f"用户成绩 ID: {scores_data['userScore']['id']}")
|
||||
print(f"用户成绩分数: {scores_data['userScore']['total_score']}")
|
||||
else:
|
||||
print("用户在该谱面没有成绩记录")
|
||||
|
||||
# 6. 测试令牌刷新
|
||||
print("\n6. 测试令牌刷新...")
|
||||
new_token_data = refresh_token(token_data["refresh_token"])
|
||||
if new_token_data:
|
||||
print(f"新访问令牌: {new_token_data['access_token']}")
|
||||
|
||||
# 使用新令牌获取用户数据
|
||||
print("\n6. 使用新令牌获取用户数据...")
|
||||
print("\n7. 使用新令牌获取用户数据...")
|
||||
user_data = get_current_user(new_token_data["access_token"])
|
||||
if user_data:
|
||||
print(f"✅ 新令牌有效,用户: {user_data['username']}")
|
||||
@@ -165,4 +196,4 @@ def main():
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
Reference in New Issue
Block a user