fxxk merge
This commit is contained in:
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
17
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
17
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyCompatibilityInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ourVersions">
|
||||||
|
<value>
|
||||||
|
<list size="4">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="3.7" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="3.11" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="3.12" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="3.13" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
10
.idea/misc.xml
generated
Normal file
10
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="osu_lazer_api" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="osu_lazer_api" project-jdk-type="Python SDK" />
|
||||||
|
<component name="PythonCompatibilityInspectionAdvertiser">
|
||||||
|
<option name="version" value="3" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/osu_lazer_api.iml" filepath="$PROJECT_DIR$/.idea/osu_lazer_api.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
14
.idea/osu_lazer_api.iml
generated
Normal file
14
.idea/osu_lazer_api.iml
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="osu_lazer_api" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PyDocumentationSettings">
|
||||||
|
<option name="format" value="PLAIN" />
|
||||||
|
<option name="myDocStringFormat" value="Plain" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,455 +0,0 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from sqlalchemy import (
|
|
||||||
DECIMAL,
|
|
||||||
JSON,
|
|
||||||
Boolean,
|
|
||||||
Column,
|
|
||||||
DateTime,
|
|
||||||
Float,
|
|
||||||
ForeignKey,
|
|
||||||
Integer,
|
|
||||||
String,
|
|
||||||
Text,
|
|
||||||
)
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
from sqlalchemy.orm import relationship
|
|
||||||
|
|
||||||
Base = declarative_base()
|
|
||||||
|
|
||||||
|
|
||||||
class User(Base):
|
|
||||||
__tablename__ = "users"
|
|
||||||
|
|
||||||
# 主键
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
|
|
||||||
# 基本信息(匹配 migrations 中的结构)
|
|
||||||
name = Column(String(32), unique=True, index=True, nullable=False) # 用户名
|
|
||||||
safe_name = Column(
|
|
||||||
String(32), unique=True, index=True, nullable=False
|
|
||||||
) # 安全用户名
|
|
||||||
email = Column(String(254), unique=True, index=True, nullable=False)
|
|
||||||
priv = Column(Integer, default=1, nullable=False) # 权限
|
|
||||||
pw_bcrypt = Column(String(60), nullable=False) # bcrypt 哈希密码
|
|
||||||
country = Column(String(2), default="CN", nullable=False) # 国家代码
|
|
||||||
|
|
||||||
# 状态和时间
|
|
||||||
silence_end = Column(Integer, default=0, nullable=False)
|
|
||||||
donor_end = Column(Integer, default=0, nullable=False)
|
|
||||||
creation_time = Column(Integer, default=0, nullable=False) # Unix 时间戳
|
|
||||||
latest_activity = Column(Integer, default=0, nullable=False) # Unix 时间戳
|
|
||||||
|
|
||||||
# 游戏相关
|
|
||||||
preferred_mode = Column(Integer, default=0, nullable=False) # 偏好游戏模式
|
|
||||||
play_style = Column(Integer, default=0, nullable=False) # 游戏风格
|
|
||||||
|
|
||||||
# 扩展信息
|
|
||||||
clan_id = Column(Integer, default=0, nullable=False)
|
|
||||||
clan_priv = Column(Integer, default=0, nullable=False)
|
|
||||||
custom_badge_name = Column(String(16))
|
|
||||||
custom_badge_icon = Column(String(64))
|
|
||||||
userpage_content = Column(String(2048))
|
|
||||||
api_key = Column(String(36), unique=True)
|
|
||||||
|
|
||||||
# 虚拟字段用于兼容性
|
|
||||||
@property
|
|
||||||
def username(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
@property
|
|
||||||
def country_code(self):
|
|
||||||
return self.country
|
|
||||||
|
|
||||||
@property
|
|
||||||
def join_date(self):
|
|
||||||
return (
|
|
||||||
datetime.fromtimestamp(self.creation_time)
|
|
||||||
if self.creation_time > 0
|
|
||||||
else datetime.utcnow()
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def last_visit(self):
|
|
||||||
return (
|
|
||||||
datetime.fromtimestamp(self.latest_activity)
|
|
||||||
if self.latest_activity > 0
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# 关联关系
|
|
||||||
lazer_profile = relationship(
|
|
||||||
"LazerUserProfile",
|
|
||||||
back_populates="user",
|
|
||||||
uselist=False,
|
|
||||||
cascade="all, delete-orphan",
|
|
||||||
)
|
|
||||||
lazer_statistics = relationship(
|
|
||||||
"LazerUserStatistics", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
lazer_achievements = relationship(
|
|
||||||
"LazerUserAchievement", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Lazer API 专用表模型
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
|
|
||||||
class LazerUserProfile(Base):
|
|
||||||
__tablename__ = "lazer_user_profiles"
|
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
|
||||||
|
|
||||||
# 基本状态字段
|
|
||||||
is_active = Column(Boolean, default=True)
|
|
||||||
is_bot = Column(Boolean, default=False)
|
|
||||||
is_deleted = Column(Boolean, default=False)
|
|
||||||
is_online = Column(Boolean, default=True)
|
|
||||||
is_supporter = Column(Boolean, default=False)
|
|
||||||
is_restricted = Column(Boolean, default=False)
|
|
||||||
session_verified = Column(Boolean, default=False)
|
|
||||||
has_supported = Column(Boolean, default=False)
|
|
||||||
pm_friends_only = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
# 基本资料字段
|
|
||||||
default_group = Column(String(50), default="default")
|
|
||||||
last_visit = Column(DateTime)
|
|
||||||
join_date = Column(DateTime)
|
|
||||||
profile_colour = Column(String(7))
|
|
||||||
profile_hue = Column(Integer)
|
|
||||||
|
|
||||||
# 社交媒体和个人资料字段
|
|
||||||
avatar_url = Column(String(500))
|
|
||||||
cover_url = Column(String(500))
|
|
||||||
discord = Column(String(100))
|
|
||||||
twitter = Column(String(100))
|
|
||||||
website = Column(String(500))
|
|
||||||
title = Column(String(100))
|
|
||||||
title_url = Column(String(500))
|
|
||||||
interests = Column(Text)
|
|
||||||
location = Column(String(100))
|
|
||||||
occupation = Column(String(100))
|
|
||||||
|
|
||||||
# 游戏相关字段
|
|
||||||
playmode = Column(String(10), default="osu")
|
|
||||||
support_level = Column(Integer, default=0)
|
|
||||||
max_blocks = Column(Integer, default=100)
|
|
||||||
max_friends = Column(Integer, default=500)
|
|
||||||
post_count = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 页面内容
|
|
||||||
page_html = Column(Text)
|
|
||||||
page_raw = Column(Text)
|
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
# 关联关系
|
|
||||||
user = relationship("User", back_populates="lazer_profile")
|
|
||||||
|
|
||||||
|
|
||||||
class LazerUserCountry(Base):
|
|
||||||
__tablename__ = "lazer_user_countries"
|
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
|
||||||
code = Column(String(2), nullable=False)
|
|
||||||
name = Column(String(100), nullable=False)
|
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
|
|
||||||
class LazerUserKudosu(Base):
|
|
||||||
__tablename__ = "lazer_user_kudosu"
|
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
|
||||||
available = Column(Integer, default=0)
|
|
||||||
total = Column(Integer, default=0)
|
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
|
|
||||||
class LazerUserCounts(Base):
|
|
||||||
__tablename__ = "lazer_user_counts"
|
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
|
||||||
|
|
||||||
# 统计计数字段
|
|
||||||
beatmap_playcounts_count = Column(Integer, default=0)
|
|
||||||
comments_count = Column(Integer, default=0)
|
|
||||||
favourite_beatmapset_count = Column(Integer, default=0)
|
|
||||||
follower_count = Column(Integer, default=0)
|
|
||||||
graveyard_beatmapset_count = Column(Integer, default=0)
|
|
||||||
guest_beatmapset_count = Column(Integer, default=0)
|
|
||||||
loved_beatmapset_count = Column(Integer, default=0)
|
|
||||||
mapping_follower_count = Column(Integer, default=0)
|
|
||||||
nominated_beatmapset_count = Column(Integer, default=0)
|
|
||||||
pending_beatmapset_count = Column(Integer, default=0)
|
|
||||||
ranked_beatmapset_count = Column(Integer, default=0)
|
|
||||||
ranked_and_approved_beatmapset_count = Column(Integer, default=0)
|
|
||||||
unranked_beatmapset_count = Column(Integer, default=0)
|
|
||||||
scores_best_count = Column(Integer, default=0)
|
|
||||||
scores_first_count = Column(Integer, default=0)
|
|
||||||
scores_pinned_count = Column(Integer, default=0)
|
|
||||||
scores_recent_count = Column(Integer, default=0)
|
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
|
|
||||||
class LazerUserStatistics(Base):
|
|
||||||
__tablename__ = "lazer_user_statistics"
|
|
||||||
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
mode = Column(String(10), nullable=False, default="osu")
|
|
||||||
|
|
||||||
# 基本命中统计
|
|
||||||
count_100 = Column(Integer, default=0)
|
|
||||||
count_300 = Column(Integer, default=0)
|
|
||||||
count_50 = Column(Integer, default=0)
|
|
||||||
count_miss = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 等级信息
|
|
||||||
level_current = Column(Integer, default=1)
|
|
||||||
level_progress = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 排名信息
|
|
||||||
global_rank = Column(Integer)
|
|
||||||
global_rank_exp = Column(Integer)
|
|
||||||
country_rank = Column(Integer)
|
|
||||||
|
|
||||||
# PP 和分数
|
|
||||||
pp = Column(DECIMAL(10, 2), default=0.00)
|
|
||||||
pp_exp = Column(DECIMAL(10, 2), default=0.00)
|
|
||||||
ranked_score = Column(Integer, default=0)
|
|
||||||
hit_accuracy = Column(DECIMAL(5, 2), default=0.00)
|
|
||||||
total_score = Column(Integer, default=0)
|
|
||||||
total_hits = Column(Integer, default=0)
|
|
||||||
maximum_combo = Column(Integer, default=0)
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# 旧的兼容性表模型(保留以便向后兼容)
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
|
|
||||||
class LegacyUserStatistics(Base):
|
|
||||||
__tablename__ = "user_statistics"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
mode = Column(String(10), nullable=False) # osu, taiko, fruits, mania
|
|
||||||
|
|
||||||
# 基本统计
|
|
||||||
count_100 = Column(Integer, default=0)
|
|
||||||
count_300 = Column(Integer, default=0)
|
|
||||||
count_50 = Column(Integer, default=0)
|
|
||||||
count_miss = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 等级信息
|
|
||||||
level_current = Column(Integer, default=1)
|
|
||||||
level_progress = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 排名信息
|
|
||||||
global_rank = Column(Integer)
|
|
||||||
global_rank_exp = Column(Integer)
|
|
||||||
country_rank = Column(Integer)
|
|
||||||
|
|
||||||
# PP 和分数
|
|
||||||
pp = Column(Float, default=0.0)
|
|
||||||
pp_exp = Column(Float, default=0.0)
|
|
||||||
ranked_score = Column(Integer, default=0)
|
|
||||||
hit_accuracy = Column(Float, default=0.0)
|
|
||||||
total_score = Column(Integer, default=0)
|
|
||||||
total_hits = Column(Integer, default=0)
|
|
||||||
maximum_combo = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 游戏统计
|
|
||||||
play_count = Column(Integer, default=0)
|
|
||||||
play_time = Column(Integer, default=0)
|
|
||||||
replays_watched_by_others = Column(Integer, default=0)
|
|
||||||
is_ranked = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
# 成绩等级计数
|
|
||||||
grade_ss = Column(Integer, default=0)
|
|
||||||
grade_ssh = Column(Integer, default=0)
|
|
||||||
grade_s = Column(Integer, default=0)
|
|
||||||
grade_sh = Column(Integer, default=0)
|
|
||||||
grade_a = Column(Integer, default=0)
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthToken(Base):
|
|
||||||
__tablename__ = "oauth_tokens"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
access_token = Column(String(255), nullable=False, index=True)
|
|
||||||
refresh_token = Column(String(255), nullable=False, index=True)
|
|
||||||
expires_at = Column(DateTime, nullable=False)
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
previous_usernames = Column(JSON, default=list)
|
|
||||||
replays_watched_counts = Column(JSON, default=list)
|
|
||||||
|
|
||||||
# 关联关系
|
|
||||||
statistics = relationship(
|
|
||||||
"UserStatistics", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
achievements = relationship(
|
|
||||||
"UserAchievement", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
team_membership = relationship(
|
|
||||||
"TeamMember", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
daily_challenge_stats = relationship(
|
|
||||||
"DailyChallengeStats",
|
|
||||||
back_populates="user",
|
|
||||||
uselist=False,
|
|
||||||
cascade="all, delete-orphan",
|
|
||||||
)
|
|
||||||
rank_history = relationship(
|
|
||||||
"RankHistory", back_populates="user", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class UserStatistics(Base):
|
|
||||||
__tablename__ = "user_statistics"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
mode = Column(String(10), nullable=False) # osu, taiko, fruits, mania
|
|
||||||
|
|
||||||
# 基本统计
|
|
||||||
count_100 = Column(Integer, default=0)
|
|
||||||
count_300 = Column(Integer, default=0)
|
|
||||||
count_50 = Column(Integer, default=0)
|
|
||||||
count_miss = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 等级信息
|
|
||||||
level_current = Column(Integer, default=1)
|
|
||||||
level_progress = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 排名信息
|
|
||||||
global_rank = Column(Integer)
|
|
||||||
global_rank_exp = Column(Integer)
|
|
||||||
country_rank = Column(Integer)
|
|
||||||
|
|
||||||
# PP 和分数
|
|
||||||
pp = Column(Float, default=0.0)
|
|
||||||
pp_exp = Column(Float, default=0.0)
|
|
||||||
ranked_score = Column(Integer, default=0)
|
|
||||||
hit_accuracy = Column(Float, default=0.0)
|
|
||||||
total_score = Column(Integer, default=0)
|
|
||||||
total_hits = Column(Integer, default=0)
|
|
||||||
maximum_combo = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 游戏统计
|
|
||||||
play_count = Column(Integer, default=0)
|
|
||||||
play_time = Column(Integer, default=0) # 秒
|
|
||||||
replays_watched_by_others = Column(Integer, default=0)
|
|
||||||
is_ranked = Column(Boolean, default=False)
|
|
||||||
|
|
||||||
# 成绩等级计数
|
|
||||||
grade_ss = Column(Integer, default=0)
|
|
||||||
grade_ssh = Column(Integer, default=0)
|
|
||||||
grade_s = Column(Integer, default=0)
|
|
||||||
grade_sh = Column(Integer, default=0)
|
|
||||||
grade_a = Column(Integer, default=0)
|
|
||||||
|
|
||||||
# 最高排名记录
|
|
||||||
rank_highest = Column(Integer)
|
|
||||||
rank_highest_updated_at = Column(DateTime)
|
|
||||||
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
||||||
|
|
||||||
# 关联关系
|
|
||||||
user = relationship("User", back_populates="statistics")
|
|
||||||
|
|
||||||
|
|
||||||
class UserAchievement(Base):
|
|
||||||
__tablename__ = "user_achievements"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
achievement_id = Column(Integer, nullable=False)
|
|
||||||
achieved_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
user = relationship("User", back_populates="achievements")
|
|
||||||
|
|
||||||
|
|
||||||
class Team(Base):
|
|
||||||
__tablename__ = "teams"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
name = Column(String(100), nullable=False)
|
|
||||||
short_name = Column(String(10), nullable=False)
|
|
||||||
flag_url = Column(String(500))
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
members = relationship(
|
|
||||||
"TeamMember", back_populates="team", cascade="all, delete-orphan"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TeamMember(Base):
|
|
||||||
__tablename__ = "team_members"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
team_id = Column(Integer, ForeignKey("teams.id"), nullable=False)
|
|
||||||
joined_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
user = relationship("User", back_populates="team_membership")
|
|
||||||
team = relationship("Team", back_populates="members")
|
|
||||||
|
|
||||||
|
|
||||||
class DailyChallengeStats(Base):
|
|
||||||
__tablename__ = "daily_challenge_stats"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False, unique=True)
|
|
||||||
|
|
||||||
daily_streak_best = Column(Integer, default=0)
|
|
||||||
daily_streak_current = Column(Integer, default=0)
|
|
||||||
last_update = Column(DateTime)
|
|
||||||
last_weekly_streak = Column(DateTime)
|
|
||||||
playcount = Column(Integer, default=0)
|
|
||||||
top_10p_placements = Column(Integer, default=0)
|
|
||||||
top_50p_placements = Column(Integer, default=0)
|
|
||||||
weekly_streak_best = Column(Integer, default=0)
|
|
||||||
weekly_streak_current = Column(Integer, default=0)
|
|
||||||
|
|
||||||
user = relationship("User", back_populates="daily_challenge_stats")
|
|
||||||
|
|
||||||
|
|
||||||
class RankHistory(Base):
|
|
||||||
__tablename__ = "rank_history"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
mode = Column(String(10), nullable=False)
|
|
||||||
rank_data = Column(JSON, nullable=False) # Array of ranks
|
|
||||||
date_recorded = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
user = relationship("User", back_populates="rank_history")
|
|
||||||
|
|
||||||
|
|
||||||
class OAuthToken(Base):
|
|
||||||
__tablename__ = "oauth_tokens"
|
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True, index=True)
|
|
||||||
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
||||||
access_token = Column(String(500), unique=True, nullable=False)
|
|
||||||
refresh_token = Column(String(500), unique=True, nullable=False)
|
|
||||||
token_type = Column(String(20), default="Bearer")
|
|
||||||
scope = Column(String(100), default="*")
|
|
||||||
expires_at = Column(DateTime, nullable=False)
|
|
||||||
created_at = Column(DateTime, default=datetime.utcnow)
|
|
||||||
|
|
||||||
user = relationship("User")
|
|
||||||
123
app/database.py
123
app/database.py
@@ -8,6 +8,7 @@ from sqlalchemy import (
|
|||||||
JSON,
|
JSON,
|
||||||
Boolean,
|
Boolean,
|
||||||
Column,
|
Column,
|
||||||
|
Date,
|
||||||
DateTime,
|
DateTime,
|
||||||
Float,
|
Float,
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
@@ -15,6 +16,7 @@ from sqlalchemy import (
|
|||||||
String,
|
String,
|
||||||
Text,
|
Text,
|
||||||
)
|
)
|
||||||
|
from sqlalchemy.dialects.mysql import TINYINT, VARCHAR
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
@@ -91,11 +93,19 @@ class User(Base):
|
|||||||
lazer_achievements = relationship(
|
lazer_achievements = relationship(
|
||||||
"LazerUserAchievement", back_populates="user", cascade="all, delete-orphan"
|
"LazerUserAchievement", back_populates="user", cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
|
lazer_profile_sections = relationship(
|
||||||
|
"LazerUserProfileSections", # 修正类名拼写(添加s)
|
||||||
|
back_populates="user",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
)
|
||||||
statistics = relationship(
|
statistics = relationship(
|
||||||
"LegacyUserStatistics", back_populates="user", cascade="all, delete-orphan"
|
"LegacyUserStatistics", back_populates="user", cascade="all, delete-orphan"
|
||||||
)
|
)
|
||||||
achievements = relationship(
|
achievements = relationship(
|
||||||
"LazerUserAchievement", back_populates="user", cascade="all, delete-orphan"
|
"LazerUserAchievement",
|
||||||
|
back_populates="user",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
overlaps="lazer_achievements",
|
||||||
)
|
)
|
||||||
team_membership = relationship(
|
team_membership = relationship(
|
||||||
"TeamMember", back_populates="user", cascade="all, delete-orphan"
|
"TeamMember", back_populates="user", cascade="all, delete-orphan"
|
||||||
@@ -115,6 +125,28 @@ class User(Base):
|
|||||||
primaryjoin="and_(User.id==UserAvatar.user_id, UserAvatar.is_active==True)",
|
primaryjoin="and_(User.id==UserAvatar.user_id, UserAvatar.is_active==True)",
|
||||||
uselist=False,
|
uselist=False,
|
||||||
)
|
)
|
||||||
|
active_banners = relationship(
|
||||||
|
"LazerUserBanners", # 原定义指向LazerUserBanners,实际应为UserAvatar
|
||||||
|
back_populates="user",
|
||||||
|
primaryjoin=(
|
||||||
|
"and_(User.id==LazerUserBanners.user_id, LazerUserBanners.is_active==True)"
|
||||||
|
),
|
||||||
|
uselist=False,
|
||||||
|
)
|
||||||
|
lazer_badges = relationship(
|
||||||
|
"LazerUserBadge", back_populates="user", cascade="all, delete-orphan"
|
||||||
|
)
|
||||||
|
lazer_monthly_playcounts = relationship(
|
||||||
|
"LazerUserMonthlyPlaycounts",
|
||||||
|
back_populates="user",
|
||||||
|
cascade="all, delete-orphan",
|
||||||
|
)
|
||||||
|
lazer_previous_usernames = relationship(
|
||||||
|
"LazerUserPreviousUsername", back_populates="user", cascade="all, delete-orphan"
|
||||||
|
)
|
||||||
|
lazer_replays_watched = relationship(
|
||||||
|
"LazerUserReplaysWatched", back_populates="user", cascade="all, delete-orphan"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -176,6 +208,20 @@ class LazerUserProfile(Base):
|
|||||||
user = relationship("User", back_populates="lazer_profile")
|
user = relationship("User", back_populates="lazer_profile")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserProfileSections(Base):
|
||||||
|
__tablename__ = "lazer_user_profile_sections"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
section_name = Column(VARCHAR(50), nullable=False)
|
||||||
|
display_order = Column(Integer)
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("User", back_populates="lazer_profile_sections")
|
||||||
|
|
||||||
|
|
||||||
class LazerUserCountry(Base):
|
class LazerUserCountry(Base):
|
||||||
__tablename__ = "lazer_user_countries"
|
__tablename__ = "lazer_user_countries"
|
||||||
|
|
||||||
@@ -280,6 +326,22 @@ class LazerUserStatistics(Base):
|
|||||||
user = relationship("User", back_populates="lazer_statistics")
|
user = relationship("User", back_populates="lazer_statistics")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserBanners(Base):
|
||||||
|
__tablename__ = "lazer_user_tournament_banners"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
tournament_id = Column(Integer, nullable=False)
|
||||||
|
image_url = Column(VARCHAR(500), nullable=False)
|
||||||
|
is_active = Column(TINYINT(1))
|
||||||
|
|
||||||
|
# 修正user关系的back_populates值
|
||||||
|
user = relationship(
|
||||||
|
"User",
|
||||||
|
back_populates="active_banners", # 改为实际存在的属性名
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LazerUserAchievement(Base):
|
class LazerUserAchievement(Base):
|
||||||
__tablename__ = "lazer_user_achievements"
|
__tablename__ = "lazer_user_achievements"
|
||||||
|
|
||||||
@@ -294,6 +356,65 @@ class LazerUserAchievement(Base):
|
|||||||
user = relationship("User", back_populates="lazer_achievements")
|
user = relationship("User", back_populates="lazer_achievements")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserBadge(Base):
|
||||||
|
__tablename__ = "lazer_user_badges"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
badge_id = Column(Integer, nullable=False)
|
||||||
|
awarded_at = Column(DateTime)
|
||||||
|
description = Column(Text)
|
||||||
|
image_url = Column(String(500))
|
||||||
|
url = Column(String(500))
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("User", back_populates="lazer_badges")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserMonthlyPlaycounts(Base):
|
||||||
|
__tablename__ = "lazer_user_monthly_playcounts"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
start_date = Column(Date, nullable=False)
|
||||||
|
play_count = Column(Integer, default=0)
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("User", back_populates="lazer_monthly_playcounts")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserPreviousUsername(Base):
|
||||||
|
__tablename__ = "lazer_user_previous_usernames"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
username = Column(String(32), nullable=False)
|
||||||
|
changed_at = Column(DateTime, nullable=False)
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("User", back_populates="lazer_previous_usernames")
|
||||||
|
|
||||||
|
|
||||||
|
class LazerUserReplaysWatched(Base):
|
||||||
|
__tablename__ = "lazer_user_replays_watched"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
||||||
|
start_date = Column(Date, nullable=False)
|
||||||
|
count = Column(Integer, default=0)
|
||||||
|
|
||||||
|
created_at = Column(DateTime, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("User", back_populates="lazer_replays_watched")
|
||||||
|
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# 旧的兼容性表模型(保留以便向后兼容)
|
# 旧的兼容性表模型(保留以便向后兼容)
|
||||||
# ============================================
|
# ============================================
|
||||||
|
|||||||
248
app/utils.py
248
app/utils.py
@@ -7,12 +7,10 @@ from app.models import (
|
|||||||
Country,
|
Country,
|
||||||
Cover,
|
Cover,
|
||||||
DailyChallengeStats,
|
DailyChallengeStats,
|
||||||
GameMode,
|
|
||||||
GradeCounts,
|
GradeCounts,
|
||||||
Kudosu,
|
Kudosu,
|
||||||
Level,
|
Level,
|
||||||
Page,
|
Page,
|
||||||
PlayStyle,
|
|
||||||
RankHighest,
|
RankHighest,
|
||||||
RankHistory,
|
RankHistory,
|
||||||
Statistics,
|
Statistics,
|
||||||
@@ -41,6 +39,13 @@ def convert_db_user_to_api_user(
|
|||||||
# 如果没有 lazer 资料,使用默认值
|
# 如果没有 lazer 资料,使用默认值
|
||||||
profile = create_default_profile(db_user)
|
profile = create_default_profile(db_user)
|
||||||
|
|
||||||
|
# 获取 Lazer 用户计数
|
||||||
|
|
||||||
|
lzrcnt = db_user.lazer_statistics
|
||||||
|
if not lzrcnt:
|
||||||
|
# 如果没有 lazer 计数,使用默认值
|
||||||
|
lzrcnt = create_default_counts()
|
||||||
|
|
||||||
# 获取指定模式的统计信息
|
# 获取指定模式的统计信息
|
||||||
user_stats = None
|
user_stats = None
|
||||||
for stat in db_user.lazer_statistics:
|
for stat in db_user.lazer_statistics:
|
||||||
@@ -53,9 +58,9 @@ def convert_db_user_to_api_user(
|
|||||||
user_stats = create_default_lazer_statistics(ruleset)
|
user_stats = create_default_lazer_statistics(ruleset)
|
||||||
|
|
||||||
# 获取国家信息
|
# 获取国家信息
|
||||||
country = Country(
|
country_code = db_user.country_code if db_user.country_code else "XX"
|
||||||
code=user_country_code, name=get_country_name(user_country_code)
|
|
||||||
)
|
country = Country(code=country_code, name=get_country_name(country_code))
|
||||||
|
|
||||||
# 获取 Kudosu 信息
|
# 获取 Kudosu 信息
|
||||||
kudosu = Kudosu(available=0, total=0)
|
kudosu = Kudosu(available=0, total=0)
|
||||||
@@ -249,11 +254,99 @@ def convert_db_user_to_api_user(
|
|||||||
if avatar_url is None:
|
if avatar_url is None:
|
||||||
avatar_url = "https://a.gu-osu.gmoe.cc/api/users/avatar/1"
|
avatar_url = "https://a.gu-osu.gmoe.cc/api/users/avatar/1"
|
||||||
|
|
||||||
|
# 处理 profile_order 列表排序
|
||||||
|
profile_order = [
|
||||||
|
"me",
|
||||||
|
"recent_activity",
|
||||||
|
"top_ranks",
|
||||||
|
"medals",
|
||||||
|
"historical",
|
||||||
|
"beatmaps",
|
||||||
|
"kudosu",
|
||||||
|
]
|
||||||
|
if profile and profile.profile_order:
|
||||||
|
profile_order = profile.profile_order
|
||||||
|
|
||||||
|
# 在convert_db_user_to_api_user函数中添加active_tournament_banners处理
|
||||||
|
active_tournament_banners = []
|
||||||
|
if (
|
||||||
|
hasattr(db_user, "lazer_tournament_banners")
|
||||||
|
and db_user.lazer_tournament_banners
|
||||||
|
):
|
||||||
|
for banner in db_user.lazer_tournament_banners:
|
||||||
|
active_tournament_banners.append(
|
||||||
|
{
|
||||||
|
"tournament_id": banner.tournament_id,
|
||||||
|
"image_url": banner.image_url,
|
||||||
|
"is_active": banner.is_active,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 在convert_db_user_to_api_user函数中添加badges处理
|
||||||
|
badges = []
|
||||||
|
if hasattr(db_user, "lazer_badges") and db_user.lazer_badges:
|
||||||
|
for badge in db_user.lazer_badges:
|
||||||
|
badges.append(
|
||||||
|
{
|
||||||
|
"badge_id": badge.badge_id,
|
||||||
|
"awarded_at": badge.awarded_at,
|
||||||
|
"description": badge.description,
|
||||||
|
"image_url": badge.image_url,
|
||||||
|
"url": badge.url,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 在convert_db_user_to_api_user函数中添加monthly_playcounts处理
|
||||||
|
monthly_playcounts = []
|
||||||
|
if (
|
||||||
|
hasattr(db_user, "lazer_monthly_playcounts")
|
||||||
|
and db_user.lazer_monthly_playcounts
|
||||||
|
):
|
||||||
|
for playcount in db_user.lazer_monthly_playcounts:
|
||||||
|
monthly_playcounts.append(
|
||||||
|
{
|
||||||
|
"start_date": playcount.start_date.isoformat()
|
||||||
|
if playcount.start_date
|
||||||
|
else None,
|
||||||
|
"play_count": playcount.play_count,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 在convert_db_user_to_api_user函数中添加previous_usernames处理
|
||||||
|
previous_usernames = []
|
||||||
|
if (
|
||||||
|
hasattr(db_user, "lazer_previous_usernames")
|
||||||
|
and db_user.lazer_previous_usernames
|
||||||
|
):
|
||||||
|
for username in db_user.lazer_previous_usernames:
|
||||||
|
previous_usernames.append(
|
||||||
|
{
|
||||||
|
"username": username.username,
|
||||||
|
"changed_at": username.changed_at.isoformat()
|
||||||
|
if username.changed_at
|
||||||
|
else None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 在convert_db_user_to_api_user函数中添加replays_watched_counts处理
|
||||||
|
replays_watched_counts = []
|
||||||
|
if hasattr(db_user, "lazer_replays_watched") and db_user.lazer_replays_watched:
|
||||||
|
for replay in db_user.lazer_replays_watched:
|
||||||
|
replays_watched_counts.append(
|
||||||
|
{
|
||||||
|
"start_date": replay.start_date.isoformat()
|
||||||
|
if replay.start_date
|
||||||
|
else None,
|
||||||
|
"count": replay.count,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# 创建用户对象
|
||||||
user = User(
|
user = User(
|
||||||
id=user_id,
|
id=user_id,
|
||||||
username=user_name,
|
username=user_name,
|
||||||
avatar_url=avatar_url, # 使用我们上面获取的头像URL
|
avatar_url=avatar_url,
|
||||||
country_code=user_country,
|
country_code=country_code,
|
||||||
default_group=profile.default_group if profile else "default",
|
default_group=profile.default_group if profile else "default",
|
||||||
is_active=profile.is_active if profile else True,
|
is_active=profile.is_active if profile else True,
|
||||||
is_bot=profile.is_bot if profile else False,
|
is_bot=profile.is_bot if profile else False,
|
||||||
@@ -261,75 +354,68 @@ def convert_db_user_to_api_user(
|
|||||||
is_online=profile.is_online if profile else True,
|
is_online=profile.is_online if profile else True,
|
||||||
is_supporter=profile.is_supporter if profile else False,
|
is_supporter=profile.is_supporter if profile else False,
|
||||||
is_restricted=profile.is_restricted if profile else False,
|
is_restricted=profile.is_restricted if profile else False,
|
||||||
last_visit=db_user.last_visit,
|
last_visit=db_user.last_visit if db_user.last_visit else None,
|
||||||
pm_friends_only=profile.pm_friends_only if profile else False,
|
pm_friends_only=profile.pm_friends_only if profile else False,
|
||||||
profile_colour=profile.profile_colour if profile else None,
|
profile_colour=profile.profile_colour if profile else None,
|
||||||
cover_url=cover_url,
|
cover_url=profile.cover_url
|
||||||
|
if profile and profile.cover_url
|
||||||
|
else "https://assets.ppy.sh/user-profile-covers/default.jpeg",
|
||||||
discord=profile.discord if profile else None,
|
discord=profile.discord if profile else None,
|
||||||
has_supported=profile.has_supported if profile else False,
|
has_supported=profile.has_supported if profile else False,
|
||||||
interests=profile.interests if profile else None,
|
interests=profile.interests if profile else None,
|
||||||
join_date=db_user.join_date,
|
join_date=profile.join_date,
|
||||||
location=profile.location if profile else None,
|
location=profile.location if profile else None,
|
||||||
max_blocks=profile.max_blocks if profile else 100,
|
max_blocks=profile.max_blocks if profile and profile.max_blocks else 100,
|
||||||
max_friends=profile.max_friends if profile else 500,
|
max_friends=profile.max_friends if profile and profile.max_friends else 500,
|
||||||
occupation=None, # 职业字段,默认为 None #待修改
|
post_count=profile.post_count if profile and profile.post_count else 0,
|
||||||
# playmode=GameMode(db_user.playmode),
|
profile_hue=profile.profile_hue if profile and profile.profile_hue else None,
|
||||||
playmode=GameMode("osu"), # 待修改
|
profile_order=profile_order, # 使用排序后的 profile_order
|
||||||
playstyle=[PlayStyle.MOUSE, PlayStyle.KEYBOARD, PlayStyle.TABLET], # 待修改
|
title=profile.title if profile else None,
|
||||||
post_count=0,
|
title_url=profile.title_url if profile else None,
|
||||||
profile_hue=None,
|
twitter=profile.twitter if profile else None,
|
||||||
profile_order=[
|
website=profile.website if profile else None,
|
||||||
"me",
|
|
||||||
"recent_activity",
|
|
||||||
"top_ranks",
|
|
||||||
"medals",
|
|
||||||
"historical",
|
|
||||||
"beatmaps",
|
|
||||||
"kudosu",
|
|
||||||
],
|
|
||||||
title=None,
|
|
||||||
title_url=None,
|
|
||||||
twitter=None,
|
|
||||||
website="https://gmoe.cc",
|
|
||||||
session_verified=True,
|
session_verified=True,
|
||||||
support_level=0,
|
support_level=profile.support_level if profile else 0,
|
||||||
country=country,
|
country=country,
|
||||||
cover=cover,
|
cover=cover,
|
||||||
kudosu=kudosu,
|
kudosu=kudosu,
|
||||||
statistics=statistics,
|
statistics=statistics,
|
||||||
statistics_rulesets=statistics_rulesets,
|
statistics_rulesets=statistics_rulesets,
|
||||||
beatmap_playcounts_count=3306,
|
beatmap_playcounts_count=lzrcnt.beatmap_playcounts_count if lzrcnt else 0,
|
||||||
comments_count=0,
|
comments_count=lzrcnt.comments_count if lzrcnt else 0,
|
||||||
favourite_beatmapset_count=0,
|
favourite_beatmapset_count=lzrcnt.favourite_beatmapset_count if lzrcnt else 0,
|
||||||
follower_count=0,
|
follower_count=lzrcnt.follower_count if lzrcnt else 0,
|
||||||
graveyard_beatmapset_count=0,
|
graveyard_beatmapset_count=lzrcnt.graveyard_beatmapset_count if lzrcnt else 0,
|
||||||
guest_beatmapset_count=0,
|
guest_beatmapset_count=lzrcnt.guest_beatmapset_count if lzrcnt else 0,
|
||||||
loved_beatmapset_count=0,
|
loved_beatmapset_count=lzrcnt.loved_beatmapset_count if lzrcnt else 0,
|
||||||
mapping_follower_count=0,
|
mapping_follower_count=lzrcnt.mapping_follower_count if lzrcnt else 0,
|
||||||
nominated_beatmapset_count=0,
|
nominated_beatmapset_count=lzrcnt.nominated_beatmapset_count if lzrcnt else 0,
|
||||||
pending_beatmapset_count=0,
|
pending_beatmapset_count=lzrcnt.pending_beatmapset_count if lzrcnt else 0,
|
||||||
ranked_beatmapset_count=0,
|
ranked_beatmapset_count=lzrcnt.ranked_beatmapset_count if lzrcnt else 0,
|
||||||
ranked_and_approved_beatmapset_count=0,
|
ranked_and_approved_beatmapset_count=lzrcnt.ranked_and_approved_beatmapset_count
|
||||||
unranked_beatmapset_count=0,
|
if lzrcnt
|
||||||
scores_best_count=0,
|
else 0,
|
||||||
scores_first_count=0,
|
unranked_beatmapset_count=lzrcnt.unranked_beatmapset_count if lzrcnt else 0,
|
||||||
scores_pinned_count=0,
|
scores_best_count=lzrcnt.scores_best_count if lzrcnt else 0,
|
||||||
scores_recent_count=0,
|
scores_first_count=lzrcnt.scores_first_count if lzrcnt else 0,
|
||||||
account_history=[],
|
scores_pinned_count=lzrcnt.scores_pinned_count,
|
||||||
active_tournament_banner=None,
|
scores_recent_count=lzrcnt.scores_recent_count if lzrcnt else 0,
|
||||||
active_tournament_banners=[],
|
account_history=[], # TODO: 获取用户历史账户信息
|
||||||
badges=[],
|
# active_tournament_banner=len(active_tournament_banners),
|
||||||
|
active_tournament_banners=active_tournament_banners,
|
||||||
|
badges=badges,
|
||||||
current_season_stats=None,
|
current_season_stats=None,
|
||||||
daily_challenge_user_stats=None,
|
daily_challenge_user_stats=None,
|
||||||
groups=[],
|
groups=[],
|
||||||
monthly_playcounts=[],
|
monthly_playcounts=monthly_playcounts,
|
||||||
# page=Page(html=db_user.page_html, raw=db_user.page_raw),
|
page=Page(html=profile.page_html, raw=profile.page_raw)
|
||||||
page=Page(), # Provide a default Page object
|
if profile.page_html or profile.page_raw
|
||||||
previous_usernames=[],
|
else Page(),
|
||||||
|
previous_usernames=previous_usernames,
|
||||||
rank_highest=rank_highest,
|
rank_highest=rank_highest,
|
||||||
rank_history=rank_history,
|
rank_history=rank_history,
|
||||||
rankHistory=rank_history, # 兼容性别名
|
rankHistory=rank_history,
|
||||||
replays_watched_counts=[],
|
replays_watched_counts=replays_watched_counts,
|
||||||
team=team,
|
team=team,
|
||||||
user_achievements=user_achievements,
|
user_achievements=user_achievements,
|
||||||
)
|
)
|
||||||
@@ -358,6 +444,7 @@ def get_country_name(country_code: str) -> str:
|
|||||||
def create_default_profile(db_user: DBUser):
|
def create_default_profile(db_user: DBUser):
|
||||||
"""创建默认的用户资料"""
|
"""创建默认的用户资料"""
|
||||||
|
|
||||||
|
# 完善 MockProfile 类定义
|
||||||
class MockProfile:
|
class MockProfile:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.is_active = True
|
self.is_active = True
|
||||||
@@ -371,7 +458,7 @@ def create_default_profile(db_user: DBUser):
|
|||||||
self.pm_friends_only = False
|
self.pm_friends_only = False
|
||||||
self.default_group = "default"
|
self.default_group = "default"
|
||||||
self.last_visit = None
|
self.last_visit = None
|
||||||
self.join_date = db_user.join_date
|
self.join_date = db_user.join_date if db_user else datetime.utcnow()
|
||||||
self.profile_colour = None
|
self.profile_colour = None
|
||||||
self.profile_hue = None
|
self.profile_hue = None
|
||||||
self.avatar_url = None
|
self.avatar_url = None
|
||||||
@@ -389,8 +476,23 @@ def create_default_profile(db_user: DBUser):
|
|||||||
self.max_blocks = 100
|
self.max_blocks = 100
|
||||||
self.max_friends = 500
|
self.max_friends = 500
|
||||||
self.post_count = 0
|
self.post_count = 0
|
||||||
self.page_html = None
|
# 添加profile_order字段
|
||||||
self.page_raw = None
|
self.profile_order = [
|
||||||
|
"me",
|
||||||
|
"recent_activity",
|
||||||
|
"top_ranks",
|
||||||
|
"medals",
|
||||||
|
"historical",
|
||||||
|
"beatmaps",
|
||||||
|
"kudosu",
|
||||||
|
]
|
||||||
|
self.page_html = ""
|
||||||
|
self.page_raw = ""
|
||||||
|
# 在MockProfile类中添加active_tournament_banners字段
|
||||||
|
self.active_tournament_banners = (
|
||||||
|
MockLazerTournamentBanner.create_default_banners()
|
||||||
|
)
|
||||||
|
self.active_tournament_banners = [] # 默认空列表
|
||||||
|
|
||||||
return MockProfile()
|
return MockProfile()
|
||||||
|
|
||||||
@@ -413,11 +515,11 @@ def create_default_lazer_statistics(mode: str):
|
|||||||
self.pp_exp = 0.0
|
self.pp_exp = 0.0
|
||||||
self.ranked_score = 0
|
self.ranked_score = 0
|
||||||
self.hit_accuracy = 0.0
|
self.hit_accuracy = 0.0
|
||||||
self.play_count = 0
|
|
||||||
self.play_time = 0
|
|
||||||
self.total_score = 0
|
self.total_score = 0
|
||||||
self.total_hits = 0
|
self.total_hits = 0
|
||||||
self.maximum_combo = 0
|
self.maximum_combo = 0
|
||||||
|
self.play_count = 0
|
||||||
|
self.play_time = 0
|
||||||
self.replays_watched_by_others = 0
|
self.replays_watched_by_others = 0
|
||||||
self.is_ranked = False
|
self.is_ranked = False
|
||||||
self.grade_ss = 0
|
self.grade_ss = 0
|
||||||
@@ -459,7 +561,10 @@ def create_default_counts():
|
|||||||
|
|
||||||
class MockCounts:
|
class MockCounts:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
self.recent_scores_count = None
|
||||||
self.beatmap_playcounts_count = 0
|
self.beatmap_playcounts_count = 0
|
||||||
|
self.scores_first_count = 0
|
||||||
|
self.scores_pinned_count = 0
|
||||||
self.comments_count = 0
|
self.comments_count = 0
|
||||||
self.favourite_beatmapset_count = 0
|
self.favourite_beatmapset_count = 0
|
||||||
self.follower_count = 0
|
self.follower_count = 0
|
||||||
@@ -478,3 +583,18 @@ def create_default_counts():
|
|||||||
self.scores_recent_count = 0
|
self.scores_recent_count = 0
|
||||||
|
|
||||||
return MockCounts()
|
return MockCounts()
|
||||||
|
|
||||||
|
|
||||||
|
class MockLazerTournamentBanner:
|
||||||
|
def __init__(self, tournament_id: int, image_url: str, is_active: bool = True):
|
||||||
|
self.tournament_id = tournament_id
|
||||||
|
self.image_url = image_url
|
||||||
|
self.is_active = is_active
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create_default_banners():
|
||||||
|
"""创建默认的锦标赛横幅配置"""
|
||||||
|
return [
|
||||||
|
MockLazerTournamentBanner(1, "https://example.com/banner1.jpg", True),
|
||||||
|
MockLazerTournamentBanner(2, "https://example.com/banner2.jpg", False),
|
||||||
|
]
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ from app.auth import get_password_hash
|
|||||||
from app.database import (
|
from app.database import (
|
||||||
Base,
|
Base,
|
||||||
DailyChallengeStats,
|
DailyChallengeStats,
|
||||||
LazerUserStatistics as UserStatistics,
|
LazerUserStatistics,
|
||||||
RankHistory,
|
RankHistory,
|
||||||
User,
|
User,
|
||||||
UserAchievement,
|
UserAchievement,
|
||||||
)
|
)
|
||||||
from app.dependencies import engine, get_db
|
from app.dependencies.database import engine, get_db
|
||||||
|
|
||||||
# 创建所有表
|
# 创建所有表
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
@@ -58,92 +58,92 @@ def create_sample_user():
|
|||||||
custom_badge_icon=None,
|
custom_badge_icon=None,
|
||||||
userpage_content="「世界に忘れられた」",
|
userpage_content="「世界に忘れられた」",
|
||||||
api_key=None,
|
api_key=None,
|
||||||
# # 兼容性字段
|
# # 兼容性字段
|
||||||
# avatar_url="https://a.ppy.sh/15651670?1732362658.jpeg",
|
# avatar_url="https://a.ppy.sh/15651670?1732362658.jpeg",
|
||||||
# cover_url="https://assets.ppy.sh/user-profile-covers/15651670/0fc7b77adef39765a570e7f535bc383e5a848850d41a8943f8857984330b8bc6.jpeg",
|
# cover_url="https://assets.ppy.sh/user-profile-covers/15651670/0fc7b77adef39765a570e7f535bc383e5a848850d41a8943f8857984330b8bc6.jpeg",
|
||||||
# has_supported=True,
|
# has_supported=True,
|
||||||
# interests="「世界に忘れられた」",
|
# interests="「世界に忘れられた」",
|
||||||
# location="咕谷国",
|
# location="咕谷国",
|
||||||
# website="https://gmoe.cc",
|
# website="https://gmoe.cc",
|
||||||
# playstyle=["mouse", "keyboard", "tablet"],
|
# playstyle=["mouse", "keyboard", "tablet"],
|
||||||
# profile_order=[
|
# profile_order=[
|
||||||
# "me",
|
# "me",
|
||||||
# "recent_activity",
|
# "recent_activity",
|
||||||
# "top_ranks",
|
# "top_ranks",
|
||||||
# "medals",
|
# "medals",
|
||||||
# "historical",
|
# "historical",
|
||||||
# "beatmaps",
|
# "beatmaps",
|
||||||
# "kudosu",
|
# "kudosu",
|
||||||
# ],
|
# ],
|
||||||
# beatmap_playcounts_count=3306,
|
# beatmap_playcounts_count=3306,
|
||||||
# favourite_beatmapset_count=15,
|
# favourite_beatmapset_count=15,
|
||||||
# follower_count=98,
|
# follower_count=98,
|
||||||
# graveyard_beatmapset_count=7,
|
# graveyard_beatmapset_count=7,
|
||||||
# mapping_follower_count=1,
|
# mapping_follower_count=1,
|
||||||
# previous_usernames=["hehejun"],
|
# previous_usernames=["hehejun"],
|
||||||
# monthly_playcounts=[
|
# monthly_playcounts=[
|
||||||
# {"start_date": "2019-11-01", "count": 43},
|
# {"start_date": "2019-11-01", "count": 43},
|
||||||
# {"start_date": "2020-04-01", "count": 216},
|
# {"start_date": "2020-04-01", "count": 216},
|
||||||
# {"start_date": "2020-05-01", "count": 656},
|
# {"start_date": "2020-05-01", "count": 656},
|
||||||
# {"start_date": "2020-07-01", "count": 158},
|
# {"start_date": "2020-07-01", "count": 158},
|
||||||
# {"start_date": "2020-08-01", "count": 174},
|
# {"start_date": "2020-08-01", "count": 174},
|
||||||
# {"start_date": "2020-10-01", "count": 13},
|
# {"start_date": "2020-10-01", "count": 13},
|
||||||
# {"start_date": "2020-11-01", "count": 52},
|
# {"start_date": "2020-11-01", "count": 52},
|
||||||
# {"start_date": "2020-12-01", "count": 140},
|
# {"start_date": "2020-12-01", "count": 140},
|
||||||
# {"start_date": "2021-01-01", "count": 359},
|
# {"start_date": "2021-01-01", "count": 359},
|
||||||
# {"start_date": "2021-02-01", "count": 452},
|
# {"start_date": "2021-02-01", "count": 452},
|
||||||
# {"start_date": "2021-03-01", "count": 77},
|
# {"start_date": "2021-03-01", "count": 77},
|
||||||
# {"start_date": "2021-04-01", "count": 114},
|
# {"start_date": "2021-04-01", "count": 114},
|
||||||
# {"start_date": "2021-05-01", "count": 270},
|
# {"start_date": "2021-05-01", "count": 270},
|
||||||
# {"start_date": "2021-06-01", "count": 148},
|
# {"start_date": "2021-06-01", "count": 148},
|
||||||
# {"start_date": "2021-07-01", "count": 246},
|
# {"start_date": "2021-07-01", "count": 246},
|
||||||
# {"start_date": "2021-08-01", "count": 56},
|
# {"start_date": "2021-08-01", "count": 56},
|
||||||
# {"start_date": "2021-09-01", "count": 136},
|
# {"start_date": "2021-09-01", "count": 136},
|
||||||
# {"start_date": "2021-10-01", "count": 45},
|
# {"start_date": "2021-10-01", "count": 45},
|
||||||
# {"start_date": "2021-11-01", "count": 98},
|
# {"start_date": "2021-11-01", "count": 98},
|
||||||
# {"start_date": "2021-12-01", "count": 54},
|
# {"start_date": "2021-12-01", "count": 54},
|
||||||
# {"start_date": "2022-01-01", "count": 88},
|
# {"start_date": "2022-01-01", "count": 88},
|
||||||
# {"start_date": "2022-02-01", "count": 45},
|
# {"start_date": "2022-02-01", "count": 45},
|
||||||
# {"start_date": "2022-03-01", "count": 6},
|
# {"start_date": "2022-03-01", "count": 6},
|
||||||
# {"start_date": "2022-04-01", "count": 54},
|
# {"start_date": "2022-04-01", "count": 54},
|
||||||
# {"start_date": "2022-05-01", "count": 105},
|
# {"start_date": "2022-05-01", "count": 105},
|
||||||
# {"start_date": "2022-06-01", "count": 37},
|
# {"start_date": "2022-06-01", "count": 37},
|
||||||
# {"start_date": "2022-07-01", "count": 88},
|
# {"start_date": "2022-07-01", "count": 88},
|
||||||
# {"start_date": "2022-08-01", "count": 7},
|
# {"start_date": "2022-08-01", "count": 7},
|
||||||
# {"start_date": "2022-09-01", "count": 9},
|
# {"start_date": "2022-09-01", "count": 9},
|
||||||
# {"start_date": "2022-10-01", "count": 6},
|
# {"start_date": "2022-10-01", "count": 6},
|
||||||
# {"start_date": "2022-11-01", "count": 2},
|
# {"start_date": "2022-11-01", "count": 2},
|
||||||
# {"start_date": "2022-12-01", "count": 16},
|
# {"start_date": "2022-12-01", "count": 16},
|
||||||
# {"start_date": "2023-01-01", "count": 7},
|
# {"start_date": "2023-01-01", "count": 7},
|
||||||
# {"start_date": "2023-04-01", "count": 16},
|
# {"start_date": "2023-04-01", "count": 16},
|
||||||
# {"start_date": "2023-05-01", "count": 3},
|
# {"start_date": "2023-05-01", "count": 3},
|
||||||
# {"start_date": "2023-06-01", "count": 8},
|
# {"start_date": "2023-06-01", "count": 8},
|
||||||
# {"start_date": "2023-07-01", "count": 23},
|
# {"start_date": "2023-07-01", "count": 23},
|
||||||
# {"start_date": "2023-08-01", "count": 3},
|
# {"start_date": "2023-08-01", "count": 3},
|
||||||
# {"start_date": "2023-09-01", "count": 1},
|
# {"start_date": "2023-09-01", "count": 1},
|
||||||
# {"start_date": "2023-10-01", "count": 25},
|
# {"start_date": "2023-10-01", "count": 25},
|
||||||
# {"start_date": "2023-11-01", "count": 160},
|
# {"start_date": "2023-11-01", "count": 160},
|
||||||
# {"start_date": "2023-12-01", "count": 306},
|
# {"start_date": "2023-12-01", "count": 306},
|
||||||
# {"start_date": "2024-01-01", "count": 735},
|
# {"start_date": "2024-01-01", "count": 735},
|
||||||
# {"start_date": "2024-02-01", "count": 420},
|
# {"start_date": "2024-02-01", "count": 420},
|
||||||
# {"start_date": "2024-03-01", "count": 549},
|
# {"start_date": "2024-03-01", "count": 549},
|
||||||
# {"start_date": "2024-04-01", "count": 466},
|
# {"start_date": "2024-04-01", "count": 466},
|
||||||
# {"start_date": "2024-05-01", "count": 333},
|
# {"start_date": "2024-05-01", "count": 333},
|
||||||
# {"start_date": "2024-06-01", "count": 1126},
|
# {"start_date": "2024-06-01", "count": 1126},
|
||||||
# {"start_date": "2024-07-01", "count": 534},
|
# {"start_date": "2024-07-01", "count": 534},
|
||||||
# {"start_date": "2024-08-01", "count": 280},
|
# {"start_date": "2024-08-01", "count": 280},
|
||||||
# {"start_date": "2024-09-01", "count": 116},
|
# {"start_date": "2024-09-01", "count": 116},
|
||||||
# {"start_date": "2024-10-01", "count": 120},
|
# {"start_date": "2024-10-01", "count": 120},
|
||||||
# {"start_date": "2024-11-01", "count": 332},
|
# {"start_date": "2024-11-01", "count": 332},
|
||||||
# {"start_date": "2024-12-01", "count": 243},
|
# {"start_date": "2024-12-01", "count": 243},
|
||||||
# {"start_date": "2025-01-01", "count": 122},
|
# {"start_date": "2025-01-01", "count": 122},
|
||||||
# {"start_date": "2025-02-01", "count": 379},
|
# {"start_date": "2025-02-01", "count": 379},
|
||||||
# {"start_date": "2025-03-01", "count": 278},
|
# {"start_date": "2025-03-01", "count": 278},
|
||||||
# {"start_date": "2025-04-01", "count": 296},
|
# {"start_date": "2025-04-01", "count": 296},
|
||||||
# {"start_date": "2025-05-01", "count": 964},
|
# {"start_date": "2025-05-01", "count": 964},
|
||||||
# {"start_date": "2025-06-01", "count": 821},
|
# {"start_date": "2025-06-01", "count": 821},
|
||||||
# {"start_date": "2025-07-01", "count": 230},
|
# {"start_date": "2025-07-01", "count": 230},
|
||||||
# ],
|
# ],
|
||||||
)
|
)
|
||||||
|
|
||||||
db.add(user)
|
db.add(user)
|
||||||
@@ -151,7 +151,7 @@ def create_sample_user():
|
|||||||
db.refresh(user)
|
db.refresh(user)
|
||||||
|
|
||||||
# 创建 osu! 模式统计
|
# 创建 osu! 模式统计
|
||||||
osu_stats = UserStatistics(
|
osu_stats = LazerUserStatistics(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
mode="osu",
|
mode="osu",
|
||||||
count_100=276274,
|
count_100=276274,
|
||||||
@@ -182,7 +182,7 @@ def create_sample_user():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 创建 taiko 模式统计
|
# 创建 taiko 模式统计
|
||||||
taiko_stats = UserStatistics(
|
taiko_stats = LazerUserStatistics(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
mode="taiko",
|
mode="taiko",
|
||||||
count_100=160,
|
count_100=160,
|
||||||
@@ -205,7 +205,7 @@ def create_sample_user():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 创建 fruits 模式统计
|
# 创建 fruits 模式统计
|
||||||
fruits_stats = UserStatistics(
|
fruits_stats = LazerUserStatistics(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
mode="fruits",
|
mode="fruits",
|
||||||
count_100=109,
|
count_100=109,
|
||||||
@@ -229,7 +229,7 @@ def create_sample_user():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 创建 mania 模式统计
|
# 创建 mania 模式统计
|
||||||
mania_stats = UserStatistics(
|
mania_stats = LazerUserStatistics(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
mode="mania",
|
mode="mania",
|
||||||
count_100=7867,
|
count_100=7867,
|
||||||
|
|||||||
Reference in New Issue
Block a user