From b0a7278daf8f92f373ee63b37454da7a1e2e0e77 Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Sun, 10 Aug 2025 04:39:04 +0000 Subject: [PATCH] chore(all): remove unused files --- .idea/.gitignore | 3 - .idea/inspectionProfiles/Project_Default.xml | 17 - .../inspectionProfiles/profiles_settings.xml | 6 - .idea/misc.xml | 10 - .idea/modules.xml | 8 - .idea/osu_lazer_api.iml | 14 - .idea/vcs.xml | 6 - DATA_SYNC_GUIDE.md | 140 ----- create_sample_data.py | 242 --------- migrations_old/add_lazer_rank_fields.sql | 16 - migrations_old/add_missing_fields.sql | 421 --------------- migrations_old/base.sql | 486 ------------------ migrations_old/custom_beatmaps.sql | 209 -------- migrations_old/migrations.sql | 477 ----------------- migrations_old/sync_legacy_data.sql | 337 ------------ osu_api_example.py | 64 --- quick_sync.py | 128 ----- remove_ansi.py | 52 -- sync_data.py | 236 --------- test_api.py | 256 --------- test_lazer.py | 133 ----- test_password.py | 55 -- 22 files changed, 3316 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/osu_lazer_api.iml delete mode 100644 .idea/vcs.xml delete mode 100644 DATA_SYNC_GUIDE.md delete mode 100644 create_sample_data.py delete mode 100644 migrations_old/add_lazer_rank_fields.sql delete mode 100644 migrations_old/add_missing_fields.sql delete mode 100644 migrations_old/base.sql delete mode 100644 migrations_old/custom_beatmaps.sql delete mode 100644 migrations_old/migrations.sql delete mode 100644 migrations_old/sync_legacy_data.sql delete mode 100644 osu_api_example.py delete mode 100644 quick_sync.py delete mode 100644 remove_ansi.py delete mode 100644 sync_data.py delete mode 100644 test_api.py delete mode 100644 test_lazer.py delete mode 100644 test_password.py diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 50d9d22..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# 默认忽略的文件 -/shelf/ -/workspace.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 86f861d..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 20fc29e..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index c311805..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5fd5691..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/osu_lazer_api.iml b/.idea/osu_lazer_api.iml deleted file mode 100644 index 32e115a..0000000 --- a/.idea/osu_lazer_api.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index c8397c9..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/DATA_SYNC_GUIDE.md b/DATA_SYNC_GUIDE.md deleted file mode 100644 index f6ac41d..0000000 --- a/DATA_SYNC_GUIDE.md +++ /dev/null @@ -1,140 +0,0 @@ -# Lazer API 数据同步指南 - -本指南将帮助您将现有的 bancho.py 数据库数据同步到新的 Lazer API 专用表中。 - -## 文件说明 - -1. **`migrations_old/add_missing_fields.sql`** - 创建 Lazer API 专用表结构 -2. **`migrations_old/sync_legacy_data.sql`** - 数据同步脚本 -3. **`sync_data.py`** - 交互式数据同步工具 -4. **`quick_sync.py`** - 快速同步脚本(使用项目配置) - -## 使用方法 - -### 方法一:快速同步(推荐) - -如果您已经配置好了项目的数据库连接,可以直接使用快速同步脚本: - -```bash -python quick_sync.py -``` - -此脚本会: -1. 自动读取项目配置中的数据库连接信息 -2. 创建 Lazer API 专用表结构 -3. 同步现有数据到新表 - -### 方法二:交互式同步 - -如果需要使用不同的数据库连接配置: - -```bash -python sync_data.py -``` - -此脚本会: -1. 交互式地询问数据库连接信息 -2. 检查必要表是否存在 -3. 显示详细的同步过程和结果 - -### 方法三:手动执行 SQL - -如果您熟悉 SQL 操作,可以手动执行: - -```bash -# 1. 创建表结构 -mysql -u username -p database_name < migrations_old/add_missing_fields.sql - -# 2. 同步数据 -mysql -u username -p database_name < migrations_old/sync_legacy_data.sql -``` - -## 同步内容 - -### 创建的新表 - -- `lazer_user_profiles` - 用户扩展资料 -- `lazer_user_countries` - 用户国家信息 -- `lazer_user_kudosu` - 用户 Kudosu 统计 -- `lazer_user_counts` - 用户各项计数统计 -- `lazer_user_statistics` - 用户游戏统计(按模式) -- `lazer_user_achievements` - 用户成就 -- `lazer_oauth_tokens` - OAuth 访问令牌 -- 其他相关表... - -### 同步的数据 - -1. **用户基本信息** - - 从 `users` 表同步基本资料 - - 自动转换时间戳格式 - - 设置合理的默认值 - -2. **游戏统计** - - 从 `stats` 表同步各模式的游戏数据 - - 计算命中精度和其他衍生统计 - -3. **用户成就** - - 从 `user_achievements` 表同步成就数据(如果存在) - -## 注意事项 - -1. **安全性** - - 脚本只会创建新表和插入数据 - - 不会修改或删除现有的原始表数据 - - 使用 `ON DUPLICATE KEY UPDATE` 避免重复插入 - -2. **兼容性** - - 兼容现有的 bancho.py 数据库结构 - - 支持标准的 osu! 数据格式 - -3. **性能** - - 大量数据可能需要较长时间 - - 建议在维护窗口期间执行 - -## 故障排除 - -### 常见错误 - -1. **"Unknown column" 错误** - ``` - ERROR 1054: Unknown column 'users.is_active' in 'field list' - ``` - **解决方案**: 确保先执行了 `add_missing_fields.sql` 创建表结构 - -2. **"Table doesn't exist" 错误** - ``` - ERROR 1146: Table 'database.users' doesn't exist - ``` - **解决方案**: 确认数据库中存在 bancho.py 的原始表 - -3. **连接错误** - ``` - ERROR 2003: Can't connect to MySQL server - ``` - **解决方案**: 检查数据库连接配置和权限 - -### 验证同步结果 - -同步完成后,可以执行以下查询验证结果: - -```sql --- 检查同步的用户数量 -SELECT COUNT(*) FROM lazer_user_profiles; - --- 查看样本数据 -SELECT - u.id, u.name, - lup.playmode, lup.is_supporter, - lus.pp, lus.play_count -FROM users u -LEFT JOIN lazer_user_profiles lup ON u.id = lup.user_id -LEFT JOIN lazer_user_statistics lus ON u.id = lus.user_id AND lus.mode = 'osu' -LIMIT 5; -``` - -## 支持 - -如果遇到问题,请: -1. 检查日志文件 `data_sync.log` -2. 确认数据库权限 -3. 验证原始表数据完整性 diff --git a/create_sample_data.py b/create_sample_data.py deleted file mode 100644 index 5dcd79a..0000000 --- a/create_sample_data.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python3 -""" -osu! API 模拟服务器的示例数据填充脚本 -""" - -from __future__ import annotations - -import asyncio -from datetime import datetime -import random - -from app.auth import get_password_hash -from app.database import ( - User, -) -from app.database.beatmap import Beatmap -from app.database.beatmapset import Beatmapset -from app.database.score import Score -from app.dependencies.database import create_tables, engine -from app.models.beatmap import BeatmapRankStatus, Genre, Language -from app.models.mods import APIMod -from app.models.score import GameMode, Rank - -from sqlmodel import select -from sqlmodel.ext.asyncio.session import AsyncSession - - -async def create_sample_user(): - """创建示例用户数据""" - async with AsyncSession(engine) as session: - async with session.begin(): - # 检查用户是否已存在 - result = await session.exec(select(User).where(User.name == "Googujiang")) - result2 = await session.exec( - select(User).where(User.name == "MingxuanGame") - ) - existing_user = result.first() - existing_user2 = result2.first() - if existing_user is not None and existing_user2 is not None: - print("示例用户已存在,跳过创建") - return - - # 当前时间戳 - # current_timestamp = int(time.time()) - join_timestamp = int(datetime(2019, 11, 29, 17, 23, 13).timestamp()) - last_visit_timestamp = int(datetime(2025, 7, 18, 16, 31, 29).timestamp()) - - # 创建用户 - user = User( - name="Googujiang", - safe_name="googujiang", # 安全用户名(小写) - email="googujiang@example.com", - priv=1, # 默认权限 - pw_bcrypt=get_password_hash("password123"), # 使用新的哈希方式 - country="JP", - silence_end=0, - donor_end=0, - creation_time=join_timestamp, - latest_activity=last_visit_timestamp, - clan_id=0, - clan_priv=0, - preferred_mode=0, # 0 = osu! - play_style=0, - custom_badge_name=None, - custom_badge_icon=None, - userpage_content="「世界に忘れられた」", - api_key=None, - ) - user2 = User( - name="MingxuanGame", - safe_name="mingxuangame", # 安全用户名(小写) - email="mingxuangame@example.com", - priv=1, # 默认权限 - pw_bcrypt=get_password_hash("password123"), # 使用新的哈希方式 - country="US", - silence_end=0, - donor_end=0, - creation_time=join_timestamp, - latest_activity=last_visit_timestamp, - clan_id=0, - clan_priv=0, - preferred_mode=0, # 0 = osu! - play_style=0, - custom_badge_name=None, - custom_badge_icon=None, - userpage_content="For love and fun!", - api_key=None, - ) - - session.add(user) - session.add(user2) - print(f"成功创建示例用户: {user.name} (ID: {user.id})") - print(f"安全用户名: {user.safe_name}") - print(f"邮箱: {user.email}") - print(f"国家: {user.country}") - print(f"成功创建示例用户: {user2.name} (ID: {user2.id})") - print(f"安全用户名: {user2.safe_name}") - print(f"邮箱: {user2.email}") - print(f"国家: {user2.country}") - - -async def create_sample_beatmap_data(): - """创建示例谱面数据""" - async with AsyncSession(engine) as session: - async with session.begin(): - user_id = random.randint(1, 1000) - # 检查谱面集是否已存在 - statement = select(Beatmapset).where(Beatmapset.id == 1) - result = await session.exec(statement) - existing_beatmapset = result.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) - - # 创建谱面 - 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) - - # 创建成绩 - score = Score( - id=1, - accuracy=0.9876, - map_md5="example_checksum", - user_id=1, - best_id=1, - build_id=None, - classic_total_score=1234567, - ended_at=datetime.now(), - has_replay=True, - max_combo=1100, - mods=[ - APIMod(acronym="HD", settings={}), - APIMod(acronym="DT", settings={}), - ], - passed=True, - playlist_item_id=None, - pp=250.5, - preserve=True, - rank=Rank.S, - room_id=None, - gamemode=GameMode.OSU, - started_at=datetime.now(), - total_score=1234567, - type="solo_score", - position=None, - beatmap_id=1, - n300=950, - n100=30, - n50=20, - nmiss=5, - ngeki=150, - nkatu=50, - nlarge_tick_miss=None, - nslider_tail_hit=None, - ) - session.add(score) - - 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() - await create_sample_user() - await create_sample_beatmap_data() - print("示例数据创建完成!") - # print(f"用户名: {user.name}") - # print("密码: password123") - # print("现在您可以使用这些凭据来测试API了。") - await engine.dispose() - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/migrations_old/add_lazer_rank_fields.sql b/migrations_old/add_lazer_rank_fields.sql deleted file mode 100644 index d811c90..0000000 --- a/migrations_old/add_lazer_rank_fields.sql +++ /dev/null @@ -1,16 +0,0 @@ --- 创建迁移日志表(如果不存在) -CREATE TABLE IF NOT EXISTS `migration_logs` ( - `id` INT AUTO_INCREMENT PRIMARY KEY, - `version` VARCHAR(50) NOT NULL, - `description` VARCHAR(255) NOT NULL, - `timestamp` DATETIME NOT NULL -); - --- 向 lazer_user_statistics 表添加缺失的字段 -ALTER TABLE `lazer_user_statistics` -ADD COLUMN IF NOT EXISTS `rank_highest` INT NULL COMMENT '最高排名' AFTER `grade_a`, -ADD COLUMN IF NOT EXISTS `rank_highest_updated_at` DATETIME NULL COMMENT '最高排名更新时间' AFTER `rank_highest`; - --- 更新日志 -INSERT INTO `migration_logs` (`version`, `description`, `timestamp`) -VALUES ('20250719', '向 lazer_user_statistics 表添加缺失的字段', NOW()); diff --git a/migrations_old/add_missing_fields.sql b/migrations_old/add_missing_fields.sql deleted file mode 100644 index 464e5fa..0000000 --- a/migrations_old/add_missing_fields.sql +++ /dev/null @@ -1,421 +0,0 @@ --- Lazer API 专用数据表创建脚本 --- 基于真实 osu! API 返回数据设计的表结构 --- 完全不修改 bancho.py 原有表结构,创建全新的 lazer 专用表 - --- ============================================ --- Lazer API 专用扩展表 --- ============================================ - --- Lazer 用户扩展信息表 -CREATE TABLE IF NOT EXISTS lazer_user_profiles ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - - -- 基本状态字段 - is_active TINYINT(1) DEFAULT 1 COMMENT '用户是否激活', - is_bot TINYINT(1) DEFAULT 0 COMMENT '是否为机器人账户', - is_deleted TINYINT(1) DEFAULT 0 COMMENT '是否已删除', - is_online TINYINT(1) DEFAULT 1 COMMENT '是否在线', - is_supporter TINYINT(1) DEFAULT 0 COMMENT '是否为支持者', - is_restricted TINYINT(1) DEFAULT 0 COMMENT '是否被限制', - session_verified TINYINT(1) DEFAULT 0 COMMENT '会话是否已验证', - has_supported TINYINT(1) DEFAULT 0 COMMENT '是否曾经支持过', - pm_friends_only TINYINT(1) DEFAULT 0 COMMENT '是否只接受好友私信', - - -- 基本资料字段 - default_group VARCHAR(50) DEFAULT 'default' COMMENT '默认用户组', - last_visit DATETIME NULL COMMENT '最后访问时间', - join_date DATETIME NULL COMMENT '加入日期', - profile_colour VARCHAR(7) NULL COMMENT '个人资料颜色', - profile_hue INT NULL COMMENT '个人资料色调', - - -- 社交媒体和个人资料字段 - avatar_url VARCHAR(500) NULL COMMENT '头像URL', - cover_url VARCHAR(500) NULL COMMENT '封面URL', - discord VARCHAR(100) NULL COMMENT 'Discord用户名', - twitter VARCHAR(100) NULL COMMENT 'Twitter用户名', - website VARCHAR(500) NULL COMMENT '个人网站', - title VARCHAR(100) NULL COMMENT '用户称号', - title_url VARCHAR(500) NULL COMMENT '称号链接', - interests TEXT NULL COMMENT '兴趣爱好', - location VARCHAR(100) NULL COMMENT '地理位置', - occupation VARCHAR(100) NULL COMMENT '职业', - - -- 游戏相关字段 - playmode VARCHAR(10) DEFAULT 'osu' COMMENT '主要游戏模式', - support_level INT DEFAULT 0 COMMENT '支持者等级', - max_blocks INT DEFAULT 100 COMMENT '最大屏蔽数量', - max_friends INT DEFAULT 500 COMMENT '最大好友数量', - post_count INT DEFAULT 0 COMMENT '帖子数量', - - -- 页面内容 - page_html TEXT NULL COMMENT '个人页面HTML', - page_raw TEXT NULL COMMENT '个人页面原始内容', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Lazer API 用户扩展资料表'; - --- 用户封面信息表 -CREATE TABLE IF NOT EXISTS lazer_user_covers ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - custom_url VARCHAR(500) NULL COMMENT '自定义封面URL', - url VARCHAR(500) NULL COMMENT '封面URL', - cover_id INT NULL COMMENT '封面ID', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户封面信息表'; - --- 用户国家信息表 -CREATE TABLE IF NOT EXISTS lazer_user_countries ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - code VARCHAR(2) NOT NULL COMMENT '国家代码', - name VARCHAR(100) NOT NULL COMMENT '国家名称', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户国家信息表'; - --- 用户 Kudosu 表 -CREATE TABLE IF NOT EXISTS lazer_user_kudosu ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - available INT DEFAULT 0 COMMENT '可用 Kudosu', - total INT DEFAULT 0 COMMENT '总 Kudosu', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户 Kudosu 表'; - --- 用户统计计数表 -CREATE TABLE IF NOT EXISTS lazer_user_counts ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - - -- 统计计数字段 - beatmap_playcounts_count INT DEFAULT 0 COMMENT '谱面游玩次数统计', - comments_count INT DEFAULT 0 COMMENT '评论数量', - favourite_beatmapset_count INT DEFAULT 0 COMMENT '收藏谱面集数量', - follower_count INT DEFAULT 0 COMMENT '关注者数量', - graveyard_beatmapset_count INT DEFAULT 0 COMMENT '坟场谱面集数量', - guest_beatmapset_count INT DEFAULT 0 COMMENT '客串谱面集数量', - loved_beatmapset_count INT DEFAULT 0 COMMENT '被喜爱谱面集数量', - mapping_follower_count INT DEFAULT 0 COMMENT '作图关注者数量', - nominated_beatmapset_count INT DEFAULT 0 COMMENT '提名谱面集数量', - pending_beatmapset_count INT DEFAULT 0 COMMENT '待审核谱面集数量', - ranked_beatmapset_count INT DEFAULT 0 COMMENT 'Ranked谱面集数量', - ranked_and_approved_beatmapset_count INT DEFAULT 0 COMMENT 'Ranked+Approved谱面集数量', - unranked_beatmapset_count INT DEFAULT 0 COMMENT '未Ranked谱面集数量', - scores_best_count INT DEFAULT 0 COMMENT '最佳成绩数量', - scores_first_count INT DEFAULT 0 COMMENT '第一名成绩数量', - scores_pinned_count INT DEFAULT 0 COMMENT '置顶成绩数量', - scores_recent_count INT DEFAULT 0 COMMENT '最近成绩数量', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Lazer API 用户统计计数表'; - --- 用户游戏风格表 (替代 playstyle JSON) -CREATE TABLE IF NOT EXISTS lazer_user_playstyles ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - style VARCHAR(50) NOT NULL COMMENT '游戏风格: mouse, keyboard, tablet, touch', - - INDEX idx_user_id (user_id), - UNIQUE KEY unique_user_style (user_id, style), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户游戏风格表'; - --- 用户个人资料显示顺序表 (替代 profile_order JSON) -CREATE TABLE IF NOT EXISTS lazer_user_profile_sections ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - section_name VARCHAR(50) NOT NULL COMMENT '部分名称', - display_order INT DEFAULT 0 COMMENT '显示顺序', - - INDEX idx_user_id (user_id), - INDEX idx_order (user_id, display_order), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户个人资料显示顺序表'; - --- 用户账户历史表 (替代 account_history JSON) -CREATE TABLE IF NOT EXISTS lazer_user_account_history ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - event_type VARCHAR(50) NOT NULL COMMENT '事件类型', - description TEXT COMMENT '事件描述', - length INT COMMENT '持续时间(秒)', - permanent TINYINT(1) DEFAULT 0 COMMENT '是否永久', - event_time DATETIME NOT NULL COMMENT '事件时间', - - INDEX idx_user_id (user_id), - INDEX idx_event_time (event_time), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户账户历史表'; - --- 用户历史用户名表 (替代 previous_usernames JSON) -CREATE TABLE IF NOT EXISTS lazer_user_previous_usernames ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - username VARCHAR(32) NOT NULL COMMENT '历史用户名', - changed_at DATETIME NOT NULL COMMENT '更改时间', - - INDEX idx_user_id (user_id), - INDEX idx_changed_at (changed_at), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户历史用户名表'; - --- 用户月度游戏次数表 (替代 monthly_playcounts JSON) -CREATE TABLE IF NOT EXISTS lazer_user_monthly_playcounts ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - start_date DATE NOT NULL COMMENT '月份开始日期', - play_count INT DEFAULT 0 COMMENT '游戏次数', - - INDEX idx_user_id (user_id), - INDEX idx_start_date (start_date), - UNIQUE KEY unique_user_month (user_id, start_date), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户月度游戏次数表'; - --- 用户最高排名表 (rank_highest) -CREATE TABLE IF NOT EXISTS lazer_user_rank_highest ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - rank_position INT NOT NULL COMMENT '最高排名位置', - updated_at DATETIME NOT NULL COMMENT '更新时间', - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户最高排名表'; - --- ============================================ --- OAuth 令牌表 (Lazer API 专用) --- ============================================ -CREATE TABLE IF NOT EXISTS lazer_oauth_tokens ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL, - access_token VARCHAR(255) NOT NULL, - refresh_token VARCHAR(255) NOT NULL, - expires_at DATETIME NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - INDEX idx_user_id (user_id), - INDEX idx_access_token (access_token), - INDEX idx_refresh_token (refresh_token), - INDEX idx_expires_at (expires_at), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Lazer API OAuth访问令牌表'; - --- ============================================ --- 用户统计数据表 (基于真实 API 数据结构) --- ============================================ - --- 用户主要统计表 (statistics 字段) -CREATE TABLE IF NOT EXISTS lazer_user_statistics ( - user_id INT NOT NULL, - mode VARCHAR(10) NOT NULL DEFAULT 'osu' COMMENT '游戏模式: osu, taiko, fruits, mania', - - -- 基本命中统计 - count_100 INT DEFAULT 0 COMMENT '100分命中数', - count_300 INT DEFAULT 0 COMMENT '300分命中数', - count_50 INT DEFAULT 0 COMMENT '50分命中数', - count_miss INT DEFAULT 0 COMMENT 'Miss数', - - -- 等级信息 - level_current INT DEFAULT 1 COMMENT '当前等级', - level_progress INT DEFAULT 0 COMMENT '等级进度', - - -- 排名信息 - global_rank INT NULL COMMENT '全球排名', - global_rank_exp INT NULL COMMENT '全球排名(实验性)', - country_rank INT NULL COMMENT '国家/地区排名', - - -- PP 和分数 - pp DECIMAL(10,2) DEFAULT 0.00 COMMENT 'Performance Points', - pp_exp DECIMAL(10,2) DEFAULT 0.00 COMMENT 'PP(实验性)', - ranked_score BIGINT DEFAULT 0 COMMENT 'Ranked分数', - hit_accuracy DECIMAL(5,2) DEFAULT 0.00 COMMENT '命中精度', - total_score BIGINT DEFAULT 0 COMMENT '总分数', - total_hits BIGINT DEFAULT 0 COMMENT '总命中数', - maximum_combo INT DEFAULT 0 COMMENT '最大连击', - - -- 游戏统计 - play_count INT DEFAULT 0 COMMENT '游戏次数', - play_time INT DEFAULT 0 COMMENT '游戏时间(秒)', - replays_watched_by_others INT DEFAULT 0 COMMENT '被观看的Replay次数', - is_ranked TINYINT(1) DEFAULT 0 COMMENT '是否有排名', - - -- 成绩等级计数 (grade_counts) - grade_ss INT DEFAULT 0 COMMENT 'SS等级数', - grade_ssh INT DEFAULT 0 COMMENT 'SSH等级数', - grade_s INT DEFAULT 0 COMMENT 'S等级数', - grade_sh INT DEFAULT 0 COMMENT 'SH等级数', - grade_a INT DEFAULT 0 COMMENT 'A等级数', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - PRIMARY KEY (user_id, mode), - INDEX idx_mode (mode), - INDEX idx_global_rank (global_rank), - INDEX idx_country_rank (country_rank), - INDEX idx_pp (pp), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Lazer API 用户游戏统计表'; - --- 每日挑战用户统计表 (daily_challenge_user_stats) -CREATE TABLE IF NOT EXISTS lazer_daily_challenge_stats ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - daily_streak_best INT DEFAULT 0 COMMENT '最佳每日连击', - daily_streak_current INT DEFAULT 0 COMMENT '当前每日连击', - last_update DATE NULL COMMENT '最后更新日期', - last_weekly_streak DATE NULL COMMENT '最后周连击日期', - playcount INT DEFAULT 0 COMMENT '游戏次数', - top_10p_placements INT DEFAULT 0 COMMENT 'Top 10% 位置数', - top_50p_placements INT DEFAULT 0 COMMENT 'Top 50% 位置数', - weekly_streak_best INT DEFAULT 0 COMMENT '最佳周连击', - weekly_streak_current INT DEFAULT 0 COMMENT '当前周连击', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='每日挑战用户统计表'; - --- 用户团队信息表 (team 字段) -CREATE TABLE IF NOT EXISTS lazer_user_teams ( - user_id INT PRIMARY KEY COMMENT '关联 users.id', - team_id INT NOT NULL COMMENT '团队ID', - team_name VARCHAR(100) NOT NULL COMMENT '团队名称', - team_short_name VARCHAR(10) NOT NULL COMMENT '团队简称', - flag_url VARCHAR(500) NULL COMMENT '团队旗帜URL', - - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户团队信息表'; - --- 用户成就表 (user_achievements) -CREATE TABLE IF NOT EXISTS lazer_user_achievements ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - achievement_id INT NOT NULL COMMENT '成就ID', - achieved_at DATETIME NOT NULL COMMENT '获得时间', - - INDEX idx_user_id (user_id), - INDEX idx_achievement_id (achievement_id), - INDEX idx_achieved_at (achieved_at), - UNIQUE KEY unique_user_achievement (user_id, achievement_id), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户成就表'; - --- 用户排名历史表 (rank_history) -CREATE TABLE IF NOT EXISTS lazer_user_rank_history ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - mode VARCHAR(10) NOT NULL DEFAULT 'osu' COMMENT '游戏模式', - day_offset INT NOT NULL COMMENT '天数偏移量(从某个基准日期开始)', - rank_position INT NOT NULL COMMENT '排名位置', - - INDEX idx_user_mode (user_id, mode), - INDEX idx_day_offset (day_offset), - UNIQUE KEY unique_user_mode_day (user_id, mode, day_offset), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户排名历史表'; - --- Replay 观看次数表 (replays_watched_counts) -CREATE TABLE IF NOT EXISTS lazer_user_replays_watched ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - start_date DATE NOT NULL COMMENT '开始日期', - count INT DEFAULT 0 COMMENT '观看次数', - - INDEX idx_user_id (user_id), - INDEX idx_start_date (start_date), - UNIQUE KEY unique_user_date (user_id, start_date), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户Replay观看次数表'; - --- 用户徽章表 (badges) -CREATE TABLE IF NOT EXISTS lazer_user_badges ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - badge_id INT NOT NULL COMMENT '徽章ID', - awarded_at DATETIME NULL COMMENT '授予时间', - description TEXT NULL COMMENT '徽章描述', - image_url VARCHAR(500) NULL COMMENT '徽章图片URL', - url VARCHAR(500) NULL COMMENT '徽章链接', - - INDEX idx_user_id (user_id), - INDEX idx_badge_id (badge_id), - UNIQUE KEY unique_user_badge (user_id, badge_id), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户徽章表'; - --- 用户组表 (groups) -CREATE TABLE IF NOT EXISTS lazer_user_groups ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - group_id INT NOT NULL COMMENT '用户组ID', - group_name VARCHAR(100) NOT NULL COMMENT '用户组名称', - group_identifier VARCHAR(50) NULL COMMENT '用户组标识符', - colour VARCHAR(7) NULL COMMENT '用户组颜色', - is_probationary TINYINT(1) DEFAULT 0 COMMENT '是否为试用期', - has_listing TINYINT(1) DEFAULT 1 COMMENT '是否显示在列表中', - has_playmodes TINYINT(1) DEFAULT 0 COMMENT '是否有游戏模式', - - INDEX idx_user_id (user_id), - INDEX idx_group_id (group_id), - UNIQUE KEY unique_user_group (user_id, group_id), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户组表'; - --- 锦标赛横幅表 (active_tournament_banners) -CREATE TABLE IF NOT EXISTS lazer_user_tournament_banners ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - tournament_id INT NOT NULL COMMENT '锦标赛ID', - image_url VARCHAR(500) NOT NULL COMMENT '横幅图片URL', - is_active TINYINT(1) DEFAULT 1 COMMENT '是否为当前活跃横幅', - - INDEX idx_user_id (user_id), - INDEX idx_tournament_id (tournament_id), - INDEX idx_is_active (is_active), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户锦标赛横幅表'; - --- ============================================ --- 占位表 (未来功能扩展用) --- ============================================ - --- 当前赛季统计占位表 -CREATE TABLE IF NOT EXISTS lazer_current_season_stats ( - id INT AUTO_INCREMENT PRIMARY KEY, - user_id INT NOT NULL COMMENT '关联 users.id', - season_id VARCHAR(50) NOT NULL COMMENT '赛季ID', - data_placeholder TEXT COMMENT '赛季数据占位', - - INDEX idx_user_id (user_id), - INDEX idx_season_id (season_id), - UNIQUE KEY unique_user_season (user_id, season_id), - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='当前赛季统计占位表'; - --- 其他功能占位表 -CREATE TABLE IF NOT EXISTS lazer_feature_placeholder ( - id INT AUTO_INCREMENT PRIMARY KEY, - feature_type VARCHAR(50) NOT NULL COMMENT '功能类型', - entity_id INT NOT NULL COMMENT '实体ID', - data_placeholder TEXT COMMENT '功能数据占位', - - INDEX idx_feature_type (feature_type), - INDEX idx_entity_id (entity_id) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='功能扩展占位表'; diff --git a/migrations_old/base.sql b/migrations_old/base.sql deleted file mode 100644 index 665723f..0000000 --- a/migrations_old/base.sql +++ /dev/null @@ -1,486 +0,0 @@ -create table achievements -( - id int auto_increment - primary key, - file varchar(128) not null, - name varchar(128) charset utf8 not null, - `desc` varchar(256) charset utf8 not null, - cond varchar(64) not null, - constraint achievements_desc_uindex - unique (`desc`), - constraint achievements_file_uindex - unique (file), - constraint achievements_name_uindex - unique (name) -); - -create table channels -( - id int auto_increment - primary key, - name varchar(32) not null, - topic varchar(256) not null, - read_priv int default 1 not null, - write_priv int default 2 not null, - auto_join tinyint(1) default 0 not null, - constraint channels_name_uindex - unique (name) -); -create index channels_auto_join_index - on channels (auto_join); - -create table clans -( - id int auto_increment - primary key, - name varchar(16) charset utf8 not null, - tag varchar(6) charset utf8 not null, - owner int not null, - created_at datetime not null, - constraint clans_name_uindex - unique (name), - constraint clans_owner_uindex - unique (owner), - constraint clans_tag_uindex - unique (tag) -); - -create table client_hashes -( - userid int not null, - osupath char(32) not null, - adapters char(32) not null, - uninstall_id char(32) not null, - disk_serial char(32) not null, - latest_time datetime not null, - occurrences int default 0 not null, - primary key (userid, osupath, adapters, uninstall_id, disk_serial) -); - -create table comments -( - id int auto_increment - primary key, - target_id int not null comment 'replay, map, or set id', - target_type enum('replay', 'map', 'song') not null, - userid int not null, - time int not null, - comment varchar(80) charset utf8 not null, - colour char(6) null comment 'rgb hex string' -); - -create table favourites -( - userid int not null, - setid int not null, - created_at int default 0 not null, - primary key (userid, setid) -); - -create table ingame_logins -( - id int auto_increment - primary key, - userid int not null, - ip varchar(45) not null comment 'maxlen for ipv6', - osu_ver date not null, - osu_stream varchar(11) not null, - datetime datetime not null -); - -create table relationships -( - user1 int not null, - user2 int not null, - type enum('friend', 'block') not null, - primary key (user1, user2) -); - -create table logs -( - id int auto_increment - primary key, - `from` int not null comment 'both from and to are playerids', - `to` int not null, - `action` varchar(32) not null, - msg varchar(2048) charset utf8 null, - time datetime not null on update CURRENT_TIMESTAMP -); - -create table mail -( - id int auto_increment - primary key, - from_id int not null, - to_id int not null, - msg varchar(2048) charset utf8 not null, - time int null, - `read` tinyint(1) default 0 not null -); - -create table maps -( - server enum('osu!', 'private') default 'osu!' not null, - id int not null, - set_id int not null, - status int not null, - md5 char(32) not null, - artist varchar(128) charset utf8 not null, - title varchar(128) charset utf8 not null, - version varchar(128) charset utf8 not null, - creator varchar(19) charset utf8 not null, - filename varchar(256) charset utf8 not null, - last_update datetime not null, - total_length int not null, - max_combo int not null, - frozen tinyint(1) default 0 not null, - plays int default 0 not null, - passes int default 0 not null, - mode tinyint(1) default 0 not null, - bpm float(12,2) default 0.00 not null, - cs float(4,2) default 0.00 not null, - ar float(4,2) default 0.00 not null, - od float(4,2) default 0.00 not null, - hp float(4,2) default 0.00 not null, - diff float(6,3) default 0.000 not null, - primary key (server, id), - constraint maps_id_uindex - unique (id), - constraint maps_md5_uindex - unique (md5) -); -create index maps_set_id_index - on maps (set_id); -create index maps_status_index - on maps (status); -create index maps_filename_index - on maps (filename); -create index maps_plays_index - on maps (plays); -create index maps_mode_index - on maps (mode); -create index maps_frozen_index - on maps (frozen); - -create table mapsets -( - server enum('osu!', 'private') default 'osu!' not null, - id int not null, - last_osuapi_check datetime default CURRENT_TIMESTAMP not null, - primary key (server, id), - constraint nmapsets_id_uindex - unique (id) -); - -create table map_requests -( - id int auto_increment - primary key, - map_id int not null, - player_id int not null, - datetime datetime not null, - active tinyint(1) not null -); - -create table performance_reports -( - scoreid bigint(20) unsigned not null, - mod_mode enum('vanilla', 'relax', 'autopilot') default 'vanilla' not null, - os varchar(64) not null, - fullscreen tinyint(1) not null, - fps_cap varchar(16) not null, - compatibility tinyint(1) not null, - version varchar(16) not null, - start_time int not null, - end_time int not null, - frame_count int not null, - spike_frames int not null, - aim_rate int not null, - completion tinyint(1) not null, - identifier varchar(128) null comment 'really don''t know much about this yet', - average_frametime int not null, - primary key (scoreid, mod_mode) -); - -create table ratings -( - userid int not null, - map_md5 char(32) not null, - rating tinyint(2) not null, - primary key (userid, map_md5) -); - -create table scores -( - id bigint unsigned auto_increment - primary key, - map_md5 char(32) not null, - score int not null, - pp float(7,3) not null, - acc float(6,3) not null, - max_combo int not null, - mods int not null, - n300 int not null, - n100 int not null, - n50 int not null, - nmiss int not null, - ngeki int not null, - nkatu int not null, - grade varchar(2) default 'N' not null, - status tinyint not null, - mode tinyint not null, - play_time datetime not null, - time_elapsed int not null, - client_flags int not null, - userid int not null, - perfect tinyint(1) not null, - online_checksum char(32) not null -); -create index scores_map_md5_index - on scores (map_md5); -create index scores_score_index - on scores (score); -create index scores_pp_index - on scores (pp); -create index scores_mods_index - on scores (mods); -create index scores_status_index - on scores (status); -create index scores_mode_index - on scores (mode); -create index scores_play_time_index - on scores (play_time); -create index scores_userid_index - on scores (userid); -create index scores_online_checksum_index - on scores (online_checksum); -create index scores_fetch_leaderboard_generic_index - on scores (map_md5, status, mode); - -create table startups -( - id int auto_increment - primary key, - ver_major tinyint not null, - ver_minor tinyint not null, - ver_micro tinyint not null, - datetime datetime not null -); - -create table stats -( - id int auto_increment, - mode tinyint(1) not null, - tscore bigint unsigned default 0 not null, - rscore bigint unsigned default 0 not null, - pp int unsigned default 0 not null, - plays int unsigned default 0 not null, - playtime int unsigned default 0 not null, - acc float(6,3) default 0.000 not null, - max_combo int unsigned default 0 not null, - total_hits int unsigned default 0 not null, - replay_views int unsigned default 0 not null, - xh_count int unsigned default 0 not null, - x_count int unsigned default 0 not null, - sh_count int unsigned default 0 not null, - s_count int unsigned default 0 not null, - a_count int unsigned default 0 not null, - primary key (id, mode) -); -create index stats_mode_index - on stats (mode); -create index stats_pp_index - on stats (pp); -create index stats_tscore_index - on stats (tscore); -create index stats_rscore_index - on stats (rscore); - -create table tourney_pool_maps -( - map_id int not null, - pool_id int not null, - mods int not null, - slot tinyint not null, - primary key (map_id, pool_id) -); -create index tourney_pool_maps_mods_slot_index - on tourney_pool_maps (mods, slot); -create index tourney_pool_maps_tourney_pools_id_fk - on tourney_pool_maps (pool_id); - -create table tourney_pools -( - id int auto_increment - primary key, - name varchar(16) not null, - created_at datetime not null, - created_by int not null -); - -create index tourney_pools_users_id_fk - on tourney_pools (created_by); - -create table user_achievements -( - userid int not null, - achid int not null, - primary key (userid, achid) -); -create index user_achievements_achid_index - on user_achievements (achid); -create index user_achievements_userid_index - on user_achievements (userid); - -create table users -( - id int auto_increment - primary key, - name varchar(32) charset utf8 not null, - safe_name varchar(32) charset utf8 not null, - email varchar(254) not null, - priv int default 1 not null, - pw_bcrypt char(60) not null, - country char(2) default 'xx' not null, - silence_end int default 0 not null, - donor_end int default 0 not null, - creation_time int default 0 not null, - latest_activity int default 0 not null, - clan_id int default 0 not null, - clan_priv tinyint(1) default 0 not null, - preferred_mode int default 0 not null, - play_style int default 0 not null, - custom_badge_name varchar(16) charset utf8 null, - custom_badge_icon varchar(64) null, - userpage_content varchar(2048) charset utf8 null, - api_key char(36) null, - constraint users_api_key_uindex - unique (api_key), - constraint users_email_uindex - unique (email), - constraint users_name_uindex - unique (name), - constraint users_safe_name_uindex - unique (safe_name) -); -create index users_priv_index - on users (priv); -create index users_clan_id_index - on users (clan_id); -create index users_clan_priv_index - on users (clan_priv); -create index users_country_index - on users (country); - -insert into users (id, name, safe_name, priv, country, silence_end, email, pw_bcrypt, creation_time, latest_activity) -values (1, 'BanchoBot', 'banchobot', 1, 'ca', 0, 'bot@akatsuki.pw', - '_______________________my_cool_bcrypt_______________________', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()); - -INSERT INTO stats (id, mode) VALUES (1, 0); # vn!std -INSERT INTO stats (id, mode) VALUES (1, 1); # vn!taiko -INSERT INTO stats (id, mode) VALUES (1, 2); # vn!catch -INSERT INTO stats (id, mode) VALUES (1, 3); # vn!mania -INSERT INTO stats (id, mode) VALUES (1, 4); # rx!std -INSERT INTO stats (id, mode) VALUES (1, 5); # rx!taiko -INSERT INTO stats (id, mode) VALUES (1, 6); # rx!catch -INSERT INTO stats (id, mode) VALUES (1, 8); # ap!std - - -# userid 2 is reserved for ppy in osu!, and the -# client will not allow users to pm this id. -# If you want this, simply remove these two lines. -alter table users auto_increment = 3; -alter table stats auto_increment = 3; - -insert into channels (name, topic, read_priv, write_priv, auto_join) -values ('#osu', 'General discussion.', 1, 2, true), - ('#announce', 'Exemplary performance and public announcements.', 1, 24576, true), - ('#lobby', 'Multiplayer lobby discussion room.', 1, 2, false), - ('#supporter', 'General discussion for supporters.', 48, 48, false), - ('#staff', 'General discussion for staff members.', 28672, 28672, true), - ('#admin', 'General discussion for administrators.', 24576, 24576, true), - ('#dev', 'General discussion for developers.', 16384, 16384, true); - -insert into achievements (id, file, name, `desc`, cond) values (1, 'osu-skill-pass-1', 'Rising Star', 'Can''t go forward without the first steps.', '(score.mods & 1 == 0) and 1 <= score.sr < 2 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (2, 'osu-skill-pass-2', 'Constellation Prize', 'Definitely not a consolation prize. Now things start getting hard!', '(score.mods & 1 == 0) and 2 <= score.sr < 3 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (3, 'osu-skill-pass-3', 'Building Confidence', 'Oh, you''ve SO got this.', '(score.mods & 1 == 0) and 3 <= score.sr < 4 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (4, 'osu-skill-pass-4', 'Insanity Approaches', 'You''re not twitching, you''re just ready.', '(score.mods & 1 == 0) and 4 <= score.sr < 5 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (5, 'osu-skill-pass-5', 'These Clarion Skies', 'Everything seems so clear now.', '(score.mods & 1 == 0) and 5 <= score.sr < 6 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (6, 'osu-skill-pass-6', 'Above and Beyond', 'A cut above the rest.', '(score.mods & 1 == 0) and 6 <= score.sr < 7 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (7, 'osu-skill-pass-7', 'Supremacy', 'All marvel before your prowess.', '(score.mods & 1 == 0) and 7 <= score.sr < 8 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (8, 'osu-skill-pass-8', 'Absolution', 'My god, you''re full of stars!', '(score.mods & 1 == 0) and 8 <= score.sr < 9 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (9, 'osu-skill-pass-9', 'Event Horizon', 'No force dares to pull you under.', '(score.mods & 1 == 0) and 9 <= score.sr < 10 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (10, 'osu-skill-pass-10', 'Phantasm', 'Fevered is your passion, extraordinary is your skill.', '(score.mods & 1 == 0) and 10 <= score.sr < 11 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (11, 'osu-skill-fc-1', 'Totality', 'All the notes. Every single one.', 'score.perfect and 1 <= score.sr < 2 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (12, 'osu-skill-fc-2', 'Business As Usual', 'Two to go, please.', 'score.perfect and 2 <= score.sr < 3 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (13, 'osu-skill-fc-3', 'Building Steam', 'Hey, this isn''t so bad.', 'score.perfect and 3 <= score.sr < 4 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (14, 'osu-skill-fc-4', 'Moving Forward', 'Bet you feel good about that.', 'score.perfect and 4 <= score.sr < 5 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (15, 'osu-skill-fc-5', 'Paradigm Shift', 'Surprisingly difficult.', 'score.perfect and 5 <= score.sr < 6 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (16, 'osu-skill-fc-6', 'Anguish Quelled', 'Don''t choke.', 'score.perfect and 6 <= score.sr < 7 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (17, 'osu-skill-fc-7', 'Never Give Up', 'Excellence is its own reward.', 'score.perfect and 7 <= score.sr < 8 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (18, 'osu-skill-fc-8', 'Aberration', 'They said it couldn''t be done. They were wrong.', 'score.perfect and 8 <= score.sr < 9 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (19, 'osu-skill-fc-9', 'Chosen', 'Reign among the Prometheans, where you belong.', 'score.perfect and 9 <= score.sr < 10 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (20, 'osu-skill-fc-10', 'Unfathomable', 'You have no equal.', 'score.perfect and 10 <= score.sr < 11 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (21, 'osu-combo-500', '500 Combo', '500 big ones! You''re moving up in the world!', '500 <= score.max_combo < 750 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (22, 'osu-combo-750', '750 Combo', '750 notes back to back? Woah.', '750 <= score.max_combo < 1000 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (23, 'osu-combo-1000', '1000 Combo', 'A thousand reasons why you rock at this game.', '1000 <= score.max_combo < 2000 and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (24, 'osu-combo-2000', '2000 Combo', 'Nothing can stop you now.', '2000 <= score.max_combo and mode_vn == 0'); -insert into achievements (id, file, name, `desc`, cond) values (25, 'taiko-skill-pass-1', 'My First Don', 'Marching to the beat of your own drum. Literally.', '(score.mods & 1 == 0) and 1 <= score.sr < 2 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (26, 'taiko-skill-pass-2', 'Katsu Katsu Katsu', 'Hora! Izuko!', '(score.mods & 1 == 0) and 2 <= score.sr < 3 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (27, 'taiko-skill-pass-3', 'Not Even Trying', 'Muzukashii? Not even.', '(score.mods & 1 == 0) and 3 <= score.sr < 4 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (28, 'taiko-skill-pass-4', 'Face Your Demons', 'The first trials are now behind you, but are you a match for the Oni?', '(score.mods & 1 == 0) and 4 <= score.sr < 5 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (29, 'taiko-skill-pass-5', 'The Demon Within', 'No rest for the wicked.', '(score.mods & 1 == 0) and 5 <= score.sr < 6 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (30, 'taiko-skill-pass-6', 'Drumbreaker', 'Too strong.', '(score.mods & 1 == 0) and 6 <= score.sr < 7 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (31, 'taiko-skill-pass-7', 'The Godfather', 'You are the Don of Dons.', '(score.mods & 1 == 0) and 7 <= score.sr < 8 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (32, 'taiko-skill-pass-8', 'Rhythm Incarnate', 'Feel the beat. Become the beat.', '(score.mods & 1 == 0) and 8 <= score.sr < 9 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (33, 'taiko-skill-fc-1', 'Keeping Time', 'Don, then katsu. Don, then katsu..', 'score.perfect and 1 <= score.sr < 2 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (34, 'taiko-skill-fc-2', 'To Your Own Beat', 'Straight and steady.', 'score.perfect and 2 <= score.sr < 3 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (35, 'taiko-skill-fc-3', 'Big Drums', 'Bigger scores to match.', 'score.perfect and 3 <= score.sr < 4 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (36, 'taiko-skill-fc-4', 'Adversity Overcome', 'Difficult? Not for you.', 'score.perfect and 4 <= score.sr < 5 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (37, 'taiko-skill-fc-5', 'Demonslayer', 'An Oni felled forevermore.', 'score.perfect and 5 <= score.sr < 6 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (38, 'taiko-skill-fc-6', 'Rhythm''s Call', 'Heralding true skill.', 'score.perfect and 6 <= score.sr < 7 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (39, 'taiko-skill-fc-7', 'Time Everlasting', 'Not a single beat escapes you.', 'score.perfect and 7 <= score.sr < 8 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (40, 'taiko-skill-fc-8', 'The Drummer''s Throne', 'Percussive brilliance befitting royalty alone.', 'score.perfect and 8 <= score.sr < 9 and mode_vn == 1'); -insert into achievements (id, file, name, `desc`, cond) values (41, 'fruits-skill-pass-1', 'A Slice Of Life', 'Hey, this fruit catching business isn''t bad.', '(score.mods & 1 == 0) and 1 <= score.sr < 2 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (42, 'fruits-skill-pass-2', 'Dashing Ever Forward', 'Fast is how you do it.', '(score.mods & 1 == 0) and 2 <= score.sr < 3 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (43, 'fruits-skill-pass-3', 'Zesty Disposition', 'No scurvy for you, not with that much fruit.', '(score.mods & 1 == 0) and 3 <= score.sr < 4 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (44, 'fruits-skill-pass-4', 'Hyperdash ON!', 'Time and distance is no obstacle to you.', '(score.mods & 1 == 0) and 4 <= score.sr < 5 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (45, 'fruits-skill-pass-5', 'It''s Raining Fruit', 'And you can catch them all.', '(score.mods & 1 == 0) and 5 <= score.sr < 6 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (46, 'fruits-skill-pass-6', 'Fruit Ninja', 'Legendary techniques.', '(score.mods & 1 == 0) and 6 <= score.sr < 7 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (47, 'fruits-skill-pass-7', 'Dreamcatcher', 'No fruit, only dreams now.', '(score.mods & 1 == 0) and 7 <= score.sr < 8 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (48, 'fruits-skill-pass-8', 'Lord of the Catch', 'Your kingdom kneels before you.', '(score.mods & 1 == 0) and 8 <= score.sr < 9 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (49, 'fruits-skill-fc-1', 'Sweet And Sour', 'Apples and oranges, literally.', 'score.perfect and 1 <= score.sr < 2 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (50, 'fruits-skill-fc-2', 'Reaching The Core', 'The seeds of future success.', 'score.perfect and 2 <= score.sr < 3 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (51, 'fruits-skill-fc-3', 'Clean Platter', 'Clean only of failure. It is completely full, otherwise.', 'score.perfect and 3 <= score.sr < 4 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (52, 'fruits-skill-fc-4', 'Between The Rain', 'No umbrella needed.', 'score.perfect and 4 <= score.sr < 5 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (53, 'fruits-skill-fc-5', 'Addicted', 'That was an overdose?', 'score.perfect and 5 <= score.sr < 6 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (54, 'fruits-skill-fc-6', 'Quickening', 'A dash above normal limits.', 'score.perfect and 6 <= score.sr < 7 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (55, 'fruits-skill-fc-7', 'Supersonic', 'Faster than is reasonably necessary.', 'score.perfect and 7 <= score.sr < 8 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (56, 'fruits-skill-fc-8', 'Dashing Scarlet', 'Speed beyond mortal reckoning.', 'score.perfect and 8 <= score.sr < 9 and mode_vn == 2'); -insert into achievements (id, file, name, `desc`, cond) values (57, 'mania-skill-pass-1', 'First Steps', 'It isn''t 9-to-5, but 1-to-9. Keys, that is.', '(score.mods & 1 == 0) and 1 <= score.sr < 2 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (58, 'mania-skill-pass-2', 'No Normal Player', 'Not anymore, at least.', '(score.mods & 1 == 0) and 2 <= score.sr < 3 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (59, 'mania-skill-pass-3', 'Impulse Drive', 'Not quite hyperspeed, but getting close.', '(score.mods & 1 == 0) and 3 <= score.sr < 4 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (60, 'mania-skill-pass-4', 'Hyperspeed', 'Woah.', '(score.mods & 1 == 0) and 4 <= score.sr < 5 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (61, 'mania-skill-pass-5', 'Ever Onwards', 'Another challenge is just around the corner.', '(score.mods & 1 == 0) and 5 <= score.sr < 6 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (62, 'mania-skill-pass-6', 'Another Surpassed', 'Is there no limit to your skills?', '(score.mods & 1 == 0) and 6 <= score.sr < 7 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (63, 'mania-skill-pass-7', 'Extra Credit', 'See me after class.', '(score.mods & 1 == 0) and 7 <= score.sr < 8 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (64, 'mania-skill-pass-8', 'Maniac', 'There''s just no stopping you.', '(score.mods & 1 == 0) and 8 <= score.sr < 9 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (65, 'mania-skill-fc-1', 'Keystruck', 'The beginning of a new story', 'score.perfect and 1 <= score.sr < 2 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (66, 'mania-skill-fc-2', 'Keying In', 'Finding your groove.', 'score.perfect and 2 <= score.sr < 3 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (67, 'mania-skill-fc-3', 'Hyperflow', 'You can *feel* the rhythm.', 'score.perfect and 3 <= score.sr < 4 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (68, 'mania-skill-fc-4', 'Breakthrough', 'Many skills mastered, rolled into one.', 'score.perfect and 4 <= score.sr < 5 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (69, 'mania-skill-fc-5', 'Everything Extra', 'Giving your all is giving everything you have.', 'score.perfect and 5 <= score.sr < 6 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (70, 'mania-skill-fc-6', 'Level Breaker', 'Finesse beyond reason', 'score.perfect and 6 <= score.sr < 7 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (71, 'mania-skill-fc-7', 'Step Up', 'A precipice rarely seen.', 'score.perfect and 7 <= score.sr < 8 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (72, 'mania-skill-fc-8', 'Behind The Veil', 'Supernatural!', 'score.perfect and 8 <= score.sr < 9 and mode_vn == 3'); -insert into achievements (id, file, name, `desc`, cond) values (73, 'all-intro-suddendeath', 'Finality', 'High stakes, no regrets.', 'score.mods == 32'); -insert into achievements (id, file, name, `desc`, cond) values (74, 'all-intro-hidden', 'Blindsight', 'I can see just perfectly', 'score.mods & 8'); -insert into achievements (id, file, name, `desc`, cond) values (75, 'all-intro-perfect', 'Perfectionist', 'Accept nothing but the best.', 'score.mods & 16384'); -insert into achievements (id, file, name, `desc`, cond) values (76, 'all-intro-hardrock', 'Rock Around The Clock', "You can\'t stop the rock.", 'score.mods & 16'); -insert into achievements (id, file, name, `desc`, cond) values (77, 'all-intro-doubletime', 'Time And A Half', "Having a right ol\' time. One and a half of them, almost.", 'score.mods & 64'); -insert into achievements (id, file, name, `desc`, cond) values (78, 'all-intro-flashlight', 'Are You Afraid Of The Dark?', "Harder than it looks, probably because it\'s hard to look.", 'score.mods & 1024'); -insert into achievements (id, file, name, `desc`, cond) values (79, 'all-intro-easy', 'Dial It Right Back', 'Sometimes you just want to take it easy.', 'score.mods & 2'); -insert into achievements (id, file, name, `desc`, cond) values (80, 'all-intro-nofail', 'Risk Averse', 'Safety nets are fun!', 'score.mods & 1'); -insert into achievements (id, file, name, `desc`, cond) values (81, 'all-intro-nightcore', 'Sweet Rave Party', 'Founded in the fine tradition of changing things that were just fine as they were.', 'score.mods & 512'); -insert into achievements (id, file, name, `desc`, cond) values (82, 'all-intro-halftime', 'Slowboat', 'You got there. Eventually.', 'score.mods & 256'); -insert into achievements (id, file, name, `desc`, cond) values (83, 'all-intro-spunout', 'Burned Out', 'One cannot always spin to win.', 'score.mods & 4096'); diff --git a/migrations_old/custom_beatmaps.sql b/migrations_old/custom_beatmaps.sql deleted file mode 100644 index b7cd122..0000000 --- a/migrations_old/custom_beatmaps.sql +++ /dev/null @@ -1,209 +0,0 @@ --- 自定义谱面系统迁移 --- 创建自定义谱面表,与官方谱面不冲突 - --- 自定义谱面集表 -CREATE TABLE custom_mapsets ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - creator_id INT NOT NULL, - title VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - artist VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - source VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '', - tags TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, - description TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, - status ENUM('pending', 'approved', 'rejected', 'loved') DEFAULT 'pending', - upload_date DATETIME DEFAULT CURRENT_TIMESTAMP, - last_update DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - osz_filename VARCHAR(255) NOT NULL, - osz_hash CHAR(32) NOT NULL, - download_count INT DEFAULT 0, - favourite_count INT DEFAULT 0, - UNIQUE KEY idx_custom_mapsets_id (id), - KEY idx_custom_mapsets_creator (creator_id), - KEY idx_custom_mapsets_status (status), - KEY idx_custom_mapsets_upload_date (upload_date), - UNIQUE KEY idx_custom_mapsets_osz_hash (osz_hash) -); - --- 自定义谱面难度表 -CREATE TABLE custom_maps ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - mapset_id BIGINT NOT NULL, - md5 CHAR(32) NOT NULL, - difficulty_name VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - filename VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - mode TINYINT DEFAULT 0 NOT NULL COMMENT '0=osu!, 1=taiko, 2=catch, 3=mania', - status ENUM('pending', 'approved', 'rejected', 'loved') DEFAULT 'pending', - - -- osu!文件基本信息 - audio_filename VARCHAR(255) DEFAULT '', - audio_lead_in INT DEFAULT 0, - preview_time INT DEFAULT -1, - countdown TINYINT DEFAULT 1, - sample_set VARCHAR(16) DEFAULT 'Normal', - stack_leniency DECIMAL(3,2) DEFAULT 0.70, - letterbox_in_breaks BOOLEAN DEFAULT FALSE, - story_fire_in_front BOOLEAN DEFAULT TRUE, - use_skin_sprites BOOLEAN DEFAULT FALSE, - always_show_playfield BOOLEAN DEFAULT FALSE, - overlay_position VARCHAR(16) DEFAULT 'NoChange', - skin_preference VARCHAR(255) DEFAULT '', - epilepsy_warning BOOLEAN DEFAULT FALSE, - countdown_offset INT DEFAULT 0, - special_style BOOLEAN DEFAULT FALSE, - widescreen_storyboard BOOLEAN DEFAULT FALSE, - samples_match_playback_rate BOOLEAN DEFAULT FALSE, - - -- 编辑器信息 - distance_spacing DECIMAL(6,3) DEFAULT 1.000, - beat_divisor TINYINT DEFAULT 4, - grid_size TINYINT DEFAULT 4, - timeline_zoom DECIMAL(6,3) DEFAULT 1.000, - - -- 谱面元数据 - title_unicode VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '', - artist_unicode VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '', - creator VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - version VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, - source VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '', - tags TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, - beatmap_id BIGINT DEFAULT 0, - beatmapset_id BIGINT DEFAULT 0, - - -- 难度设定 - hp_drain_rate DECIMAL(3,1) DEFAULT 5.0, - circle_size DECIMAL(3,1) DEFAULT 5.0, - overall_difficulty DECIMAL(3,1) DEFAULT 5.0, - approach_rate DECIMAL(3,1) DEFAULT 5.0, - slider_multiplier DECIMAL(6,3) DEFAULT 1.400, - slider_tick_rate DECIMAL(3,1) DEFAULT 1.0, - - -- 计算得出的信息 - total_length INT DEFAULT 0 COMMENT '总长度(秒)', - hit_length INT DEFAULT 0 COMMENT '击打长度(秒)', - max_combo INT DEFAULT 0, - bpm DECIMAL(8,3) DEFAULT 0.000, - star_rating DECIMAL(6,3) DEFAULT 0.000, - aim_difficulty DECIMAL(6,3) DEFAULT 0.000, - speed_difficulty DECIMAL(6,3) DEFAULT 0.000, - - -- 统计信息 - plays INT DEFAULT 0, - passes INT DEFAULT 0, - - -- 时间戳 - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - UNIQUE KEY idx_custom_maps_id (id), - UNIQUE KEY idx_custom_maps_md5 (md5), - KEY idx_custom_maps_mapset (mapset_id), - KEY idx_custom_maps_mode (mode), - KEY idx_custom_maps_status (status), - KEY idx_custom_maps_creator (creator), - KEY idx_custom_maps_star_rating (star_rating), - KEY idx_custom_maps_plays (plays), - - FOREIGN KEY (mapset_id) REFERENCES custom_mapsets(id) ON DELETE CASCADE -); - --- 自定义谱面书签表 -CREATE TABLE custom_map_bookmarks ( - user_id INT NOT NULL, - mapset_id BIGINT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (user_id, mapset_id), - FOREIGN KEY (mapset_id) REFERENCES custom_mapsets(id) ON DELETE CASCADE -); - --- 自定义谱面评分表 -CREATE TABLE custom_map_ratings ( - user_id INT NOT NULL, - map_id BIGINT NOT NULL, - rating TINYINT NOT NULL CHECK (rating >= 1 AND rating <= 10), - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (user_id, map_id), - FOREIGN KEY (map_id) REFERENCES custom_maps(id) ON DELETE CASCADE -); - --- 自定义谱面成绩表 (继承原scores表结构) -CREATE TABLE custom_scores ( - id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, - map_id BIGINT NOT NULL, - map_md5 CHAR(32) NOT NULL, - user_id INT NOT NULL, - score INT NOT NULL, - pp FLOAT(7,3) NOT NULL, - acc FLOAT(6,3) NOT NULL, - max_combo INT NOT NULL, - mods INT NOT NULL, - n300 INT NOT NULL, - n100 INT NOT NULL, - n50 INT NOT NULL, - nmiss INT NOT NULL, - ngeki INT NOT NULL, - nkatu INT NOT NULL, - grade VARCHAR(2) DEFAULT 'N' NOT NULL, - status TINYINT NOT NULL COMMENT '0=failed, 1=submitted, 2=best', - mode TINYINT NOT NULL, - play_time DATETIME NOT NULL, - time_elapsed INT NOT NULL, - client_flags INT NOT NULL, - perfect BOOLEAN NOT NULL, - online_checksum CHAR(32) NOT NULL, - - KEY idx_custom_scores_map_id (map_id), - KEY idx_custom_scores_map_md5 (map_md5), - KEY idx_custom_scores_user_id (user_id), - KEY idx_custom_scores_score (score), - KEY idx_custom_scores_pp (pp), - KEY idx_custom_scores_mods (mods), - KEY idx_custom_scores_status (status), - KEY idx_custom_scores_mode (mode), - KEY idx_custom_scores_play_time (play_time), - KEY idx_custom_scores_online_checksum (online_checksum), - KEY idx_custom_scores_leaderboard (map_md5, status, mode), - - FOREIGN KEY (map_id) REFERENCES custom_maps(id) ON DELETE CASCADE -); - --- 自定义谱面文件存储表 (用于存储.osu文件内容等) -CREATE TABLE custom_map_files ( - id BIGINT AUTO_INCREMENT PRIMARY KEY, - map_id BIGINT NOT NULL, - file_type ENUM('osu', 'audio', 'image', 'video', 'storyboard') NOT NULL, - filename VARCHAR(255) NOT NULL, - file_hash CHAR(32) NOT NULL, - file_size INT NOT NULL, - mime_type VARCHAR(100) DEFAULT '', - storage_path VARCHAR(500) NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - - UNIQUE KEY idx_custom_map_files_id (id), - KEY idx_custom_map_files_map_id (map_id), - KEY idx_custom_map_files_type (file_type), - KEY idx_custom_map_files_hash (file_hash), - - FOREIGN KEY (map_id) REFERENCES custom_maps(id) ON DELETE CASCADE -); - --- 为自定义谱面创建专门的ID生成器,避免与官方ID冲突 --- 自定义谱面ID从1000000开始 -ALTER TABLE custom_mapsets AUTO_INCREMENT = 3000000; -ALTER TABLE custom_maps AUTO_INCREMENT = 3000000; - --- 创建触发器来同步mapset信息到maps表 -DELIMITER $$ - -CREATE TRIGGER update_custom_mapset_on_map_change -AFTER UPDATE ON custom_maps -FOR EACH ROW -BEGIN - IF NEW.status != OLD.status THEN - UPDATE custom_mapsets - SET last_update = CURRENT_TIMESTAMP - WHERE id = NEW.mapset_id; - END IF; -END$$ - -DELIMITER ; diff --git a/migrations_old/migrations.sql b/migrations_old/migrations.sql deleted file mode 100644 index 8cb522d..0000000 --- a/migrations_old/migrations.sql +++ /dev/null @@ -1,477 +0,0 @@ -# This file contains any sql updates, along with the -# version they are required from. Touching this without -# at least reading utils/updater.py is certainly a bad idea :) - -# v3.0.6 -alter table users change name_safe safe_name varchar(32) not null; -alter table users drop key users_name_safe_uindex; -alter table users add constraint users_safe_name_uindex unique (safe_name); -alter table users change pw_hash pw_bcrypt char(60) not null; -insert into channels (name, topic, read_priv, write_priv, auto_join) values - ('#supporter', 'General discussion for p2w gamers.', 48, 48, false), - ('#staff', 'General discussion for the cool kids.', 28672, 28672, true), - ('#admin', 'General discussion for the cool.', 24576, 24576, true), - ('#dev', 'General discussion for the.', 16384, 16384, true); - -# v3.0.8 -alter table users modify safe_name varchar(32) charset utf8 not null; -alter table users modify name varchar(32) charset utf8 not null; -alter table mail modify msg varchar(2048) charset utf8 not null; -alter table logs modify msg varchar(2048) charset utf8 not null; -drop table if exists comments; -create table comments -( - id int auto_increment - primary key, - target_id int not null comment 'replay, map, or set id', - target_type enum('replay', 'map', 'song') not null, - userid int not null, - time int not null, - comment varchar(80) charset utf8 not null, - colour char(6) null comment 'rgb hex string' -); - -# v3.0.9 -alter table stats modify tscore_vn_std int unsigned default 0 not null; -alter table stats modify tscore_vn_taiko int unsigned default 0 not null; -alter table stats modify tscore_vn_catch int unsigned default 0 not null; -alter table stats modify tscore_vn_mania int unsigned default 0 not null; -alter table stats modify tscore_rx_std int unsigned default 0 not null; -alter table stats modify tscore_rx_taiko int unsigned default 0 not null; -alter table stats modify tscore_rx_catch int unsigned default 0 not null; -alter table stats modify tscore_ap_std int unsigned default 0 not null; -alter table stats modify rscore_vn_std int unsigned default 0 not null; -alter table stats modify rscore_vn_taiko int unsigned default 0 not null; -alter table stats modify rscore_vn_catch int unsigned default 0 not null; -alter table stats modify rscore_vn_mania int unsigned default 0 not null; -alter table stats modify rscore_rx_std int unsigned default 0 not null; -alter table stats modify rscore_rx_taiko int unsigned default 0 not null; -alter table stats modify rscore_rx_catch int unsigned default 0 not null; -alter table stats modify rscore_ap_std int unsigned default 0 not null; -alter table stats modify pp_vn_std smallint unsigned default 0 not null; -alter table stats modify pp_vn_taiko smallint unsigned default 0 not null; -alter table stats modify pp_vn_catch smallint unsigned default 0 not null; -alter table stats modify pp_vn_mania smallint unsigned default 0 not null; -alter table stats modify pp_rx_std smallint unsigned default 0 not null; -alter table stats modify pp_rx_taiko smallint unsigned default 0 not null; -alter table stats modify pp_rx_catch smallint unsigned default 0 not null; -alter table stats modify pp_ap_std smallint unsigned default 0 not null; -alter table stats modify plays_vn_std int unsigned default 0 not null; -alter table stats modify plays_vn_taiko int unsigned default 0 not null; -alter table stats modify plays_vn_catch int unsigned default 0 not null; -alter table stats modify plays_vn_mania int unsigned default 0 not null; -alter table stats modify plays_rx_std int unsigned default 0 not null; -alter table stats modify plays_rx_taiko int unsigned default 0 not null; -alter table stats modify plays_rx_catch int unsigned default 0 not null; -alter table stats modify plays_ap_std int unsigned default 0 not null; -alter table stats modify playtime_vn_std int unsigned default 0 not null; -alter table stats modify playtime_vn_taiko int unsigned default 0 not null; -alter table stats modify playtime_vn_catch int unsigned default 0 not null; -alter table stats modify playtime_vn_mania int unsigned default 0 not null; -alter table stats modify playtime_rx_std int unsigned default 0 not null; -alter table stats modify playtime_rx_taiko int unsigned default 0 not null; -alter table stats modify playtime_rx_catch int unsigned default 0 not null; -alter table stats modify playtime_ap_std int unsigned default 0 not null; -alter table stats modify maxcombo_vn_std int unsigned default 0 not null; -alter table stats modify maxcombo_vn_taiko int unsigned default 0 not null; -alter table stats modify maxcombo_vn_catch int unsigned default 0 not null; -alter table stats modify maxcombo_vn_mania int unsigned default 0 not null; -alter table stats modify maxcombo_rx_std int unsigned default 0 not null; -alter table stats modify maxcombo_rx_taiko int unsigned default 0 not null; -alter table stats modify maxcombo_rx_catch int unsigned default 0 not null; -alter table stats modify maxcombo_ap_std int unsigned default 0 not null; - -# v3.0.10 -update channels set write_priv = 24576 where name = '#announce'; - -# v3.1.0 -alter table maps modify bpm float(12,2) default 0.00 not null; -alter table stats modify tscore_vn_std bigint unsigned default 0 not null; -alter table stats modify tscore_vn_taiko bigint unsigned default 0 not null; -alter table stats modify tscore_vn_catch bigint unsigned default 0 not null; -alter table stats modify tscore_vn_mania bigint unsigned default 0 not null; -alter table stats modify tscore_rx_std bigint unsigned default 0 not null; -alter table stats modify tscore_rx_taiko bigint unsigned default 0 not null; -alter table stats modify tscore_rx_catch bigint unsigned default 0 not null; -alter table stats modify tscore_ap_std bigint unsigned default 0 not null; -alter table stats modify rscore_vn_std bigint unsigned default 0 not null; -alter table stats modify rscore_vn_taiko bigint unsigned default 0 not null; -alter table stats modify rscore_vn_catch bigint unsigned default 0 not null; -alter table stats modify rscore_vn_mania bigint unsigned default 0 not null; -alter table stats modify rscore_rx_std bigint unsigned default 0 not null; -alter table stats modify rscore_rx_taiko bigint unsigned default 0 not null; -alter table stats modify rscore_rx_catch bigint unsigned default 0 not null; -alter table stats modify rscore_ap_std bigint unsigned default 0 not null; -alter table stats modify pp_vn_std int unsigned default 0 not null; -alter table stats modify pp_vn_taiko int unsigned default 0 not null; -alter table stats modify pp_vn_catch int unsigned default 0 not null; -alter table stats modify pp_vn_mania int unsigned default 0 not null; -alter table stats modify pp_rx_std int unsigned default 0 not null; -alter table stats modify pp_rx_taiko int unsigned default 0 not null; -alter table stats modify pp_rx_catch int unsigned default 0 not null; -alter table stats modify pp_ap_std int unsigned default 0 not null; - -# v3.1.2 -create table clans -( - id int auto_increment - primary key, - name varchar(16) not null, - tag varchar(6) not null, - owner int not null, - created_at datetime not null, - constraint clans_name_uindex - unique (name), - constraint clans_owner_uindex - unique (owner), - constraint clans_tag_uindex - unique (tag) -); -alter table users add clan_id int default 0 not null; -alter table users add clan_rank tinyint(1) default 0 not null; -create table achievements -( - id int auto_increment - primary key, - file varchar(128) not null, - name varchar(128) not null, - `desc` varchar(256) not null, - cond varchar(64) not null, - mode tinyint(1) not null, - constraint achievements_desc_uindex - unique (`desc`), - constraint achievements_file_uindex - unique (file), - constraint achievements_name_uindex - unique (name) -); -create table user_achievements -( - userid int not null, - achid int not null, - primary key (userid, achid) -); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (1, 'osu-skill-pass-1', 'Rising Star', 'Can''t go forward without the first steps.', '(score.mods & 259 == 0) and 2 >= score.sr > 1', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (2, 'osu-skill-pass-2', 'Constellation Prize', 'Definitely not a consolation prize. Now things start getting hard!', '(score.mods & 259 == 0) and 3 >= score.sr > 2', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (3, 'osu-skill-pass-3', 'Building Confidence', 'Oh, you''ve SO got this.', '(score.mods & 259 == 0) and 4 >= score.sr > 3', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (4, 'osu-skill-pass-4', 'Insanity Approaches', 'You''re not twitching, you''re just ready.', '(score.mods & 259 == 0) and 5 >= score.sr > 4', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (5, 'osu-skill-pass-5', 'These Clarion Skies', 'Everything seems so clear now.', '(score.mods & 259 == 0) and 6 >= score.sr > 5', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (6, 'osu-skill-pass-6', 'Above and Beyond', 'A cut above the rest.', '(score.mods & 259 == 0) and 7 >= score.sr > 6', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (7, 'osu-skill-pass-7', 'Supremacy', 'All marvel before your prowess.', '(score.mods & 259 == 0) and 8 >= score.sr > 7', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (8, 'osu-skill-pass-8', 'Absolution', 'My god, you''re full of stars!', '(score.mods & 259 == 0) and 9 >= score.sr > 8', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (9, 'osu-skill-pass-9', 'Event Horizon', 'No force dares to pull you under.', '(score.mods & 259 == 0) and 10 >= score.sr > 9', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (10, 'osu-skill-pass-10', 'Phantasm', 'Fevered is your passion, extraordinary is your skill.', '(score.mods & 259 == 0) and 11 >= score.sr > 10', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (11, 'osu-skill-fc-1', 'Totality', 'All the notes. Every single one.', 'score.perfect and 2 >= score.sr > 1', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (12, 'osu-skill-fc-2', 'Business As Usual', 'Two to go, please.', 'score.perfect and 3 >= score.sr > 2', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (13, 'osu-skill-fc-3', 'Building Steam', 'Hey, this isn''t so bad.', 'score.perfect and 4 >= score.sr > 3', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (14, 'osu-skill-fc-4', 'Moving Forward', 'Bet you feel good about that.', 'score.perfect and 5 >= score.sr > 4', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (15, 'osu-skill-fc-5', 'Paradigm Shift', 'Surprisingly difficult.', 'score.perfect and 6 >= score.sr > 5', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (16, 'osu-skill-fc-6', 'Anguish Quelled', 'Don''t choke.', 'score.perfect and 7 >= score.sr > 6', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (17, 'osu-skill-fc-7', 'Never Give Up', 'Excellence is its own reward.', 'score.perfect and 8 >= score.sr > 7', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (18, 'osu-skill-fc-8', 'Aberration', 'They said it couldn''t be done. They were wrong.', 'score.perfect and 9 >= score.sr > 8', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (19, 'osu-skill-fc-9', 'Chosen', 'Reign among the Prometheans, where you belong.', 'score.perfect and 10 >= score.sr > 9', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (20, 'osu-skill-fc-10', 'Unfathomable', 'You have no equal.', 'score.perfect and 11 >= score.sr > 10', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (21, 'osu-combo-500', '500 Combo', '500 big ones! You''re moving up in the world!', '750 >= score.max_combo > 500', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (22, 'osu-combo-750', '750 Combo', '750 notes back to back? Woah.', '1000 >= score.max_combo > 750', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (23, 'osu-combo-1000', '1000 Combo', 'A thousand reasons why you rock at this game.', '2000 >= score.max_combo > 1000', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (24, 'osu-combo-2000', '2000 Combo', 'Nothing can stop you now.', 'score.max_combo >= 2000', 0); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (25, 'taiko-skill-pass-1', 'My First Don', 'Marching to the beat of your own drum. Literally.', '(score.mods & 259 == 0) and 2 >= score.sr > 1', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (26, 'taiko-skill-pass-2', 'Katsu Katsu Katsu', 'Hora! Izuko!', '(score.mods & 259 == 0) and 3 >= score.sr > 2', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (27, 'taiko-skill-pass-3', 'Not Even Trying', 'Muzukashii? Not even.', '(score.mods & 259 == 0) and 4 >= score.sr > 3', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (28, 'taiko-skill-pass-4', 'Face Your Demons', 'The first trials are now behind you, but are you a match for the Oni?', '(score.mods & 259 == 0) and 5 >= score.sr > 4', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (29, 'taiko-skill-pass-5', 'The Demon Within', 'No rest for the wicked.', '(score.mods & 259 == 0) and 6 >= score.sr > 5', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (30, 'taiko-skill-pass-6', 'Drumbreaker', 'Too strong.', '(score.mods & 259 == 0) and 7 >= score.sr > 6', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (31, 'taiko-skill-pass-7', 'The Godfather', 'You are the Don of Dons.', '(score.mods & 259 == 0) and 8 >= score.sr > 7', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (32, 'taiko-skill-pass-8', 'Rhythm Incarnate', 'Feel the beat. Become the beat.', '(score.mods & 259 == 0) and 9 >= score.sr > 8', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (33, 'taiko-skill-fc-1', 'Keeping Time', 'Don, then katsu. Don, then katsu..', 'score.perfect and 2 >= score.sr > 1', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (34, 'taiko-skill-fc-2', 'To Your Own Beat', 'Straight and steady.', 'score.perfect and 3 >= score.sr > 2', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (35, 'taiko-skill-fc-3', 'Big Drums', 'Bigger scores to match.', 'score.perfect and 4 >= score.sr > 3', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (36, 'taiko-skill-fc-4', 'Adversity Overcome', 'Difficult? Not for you.', 'score.perfect and 5 >= score.sr > 4', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (37, 'taiko-skill-fc-5', 'Demonslayer', 'An Oni felled forevermore.', 'score.perfect and 6 >= score.sr > 5', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (38, 'taiko-skill-fc-6', 'Rhythm''s Call', 'Heralding true skill.', 'score.perfect and 7 >= score.sr > 6', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (39, 'taiko-skill-fc-7', 'Time Everlasting', 'Not a single beat escapes you.', 'score.perfect and 8 >= score.sr > 7', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (40, 'taiko-skill-fc-8', 'The Drummer''s Throne', 'Percussive brilliance befitting royalty alone.', 'score.perfect and 9 >= score.sr > 8', 1); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (41, 'fruits-skill-pass-1', 'A Slice Of Life', 'Hey, this fruit catching business isn''t bad.', '(score.mods & 259 == 0) and 2 >= score.sr > 1', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (42, 'fruits-skill-pass-2', 'Dashing Ever Forward', 'Fast is how you do it.', '(score.mods & 259 == 0) and 3 >= score.sr > 2', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (43, 'fruits-skill-pass-3', 'Zesty Disposition', 'No scurvy for you, not with that much fruit.', '(score.mods & 259 == 0) and 4 >= score.sr > 3', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (44, 'fruits-skill-pass-4', 'Hyperdash ON!', 'Time and distance is no obstacle to you.', '(score.mods & 259 == 0) and 5 >= score.sr > 4', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (45, 'fruits-skill-pass-5', 'It''s Raining Fruit', 'And you can catch them all.', '(score.mods & 259 == 0) and 6 >= score.sr > 5', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (46, 'fruits-skill-pass-6', 'Fruit Ninja', 'Legendary techniques.', '(score.mods & 259 == 0) and 7 >= score.sr > 6', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (47, 'fruits-skill-pass-7', 'Dreamcatcher', 'No fruit, only dreams now.', '(score.mods & 259 == 0) and 8 >= score.sr > 7', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (48, 'fruits-skill-pass-8', 'Lord of the Catch', 'Your kingdom kneels before you.', '(score.mods & 259 == 0) and 9 >= score.sr > 8', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (49, 'fruits-skill-fc-1', 'Sweet And Sour', 'Apples and oranges, literally.', 'score.perfect and 2 >= score.sr > 1', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (50, 'fruits-skill-fc-2', 'Reaching The Core', 'The seeds of future success.', 'score.perfect and 3 >= score.sr > 2', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (51, 'fruits-skill-fc-3', 'Clean Platter', 'Clean only of failure. It is completely full, otherwise.', 'score.perfect and 4 >= score.sr > 3', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (52, 'fruits-skill-fc-4', 'Between The Rain', 'No umbrella needed.', 'score.perfect and 5 >= score.sr > 4', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (53, 'fruits-skill-fc-5', 'Addicted', 'That was an overdose?', 'score.perfect and 6 >= score.sr > 5', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (54, 'fruits-skill-fc-6', 'Quickening', 'A dash above normal limits.', 'score.perfect and 7 >= score.sr > 6', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (55, 'fruits-skill-fc-7', 'Supersonic', 'Faster than is reasonably necessary.', 'score.perfect and 8 >= score.sr > 7', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (56, 'fruits-skill-fc-8', 'Dashing Scarlet', 'Speed beyond mortal reckoning.', 'score.perfect and 9 >= score.sr > 8', 2); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (57, 'mania-skill-pass-1', 'First Steps', 'It isn''t 9-to-5, but 1-to-9. Keys, that is.', '(score.mods & 259 == 0) and 2 >= score.sr > 1', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (58, 'mania-skill-pass-2', 'No Normal Player', 'Not anymore, at least.', '(score.mods & 259 == 0) and 3 >= score.sr > 2', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (59, 'mania-skill-pass-3', 'Impulse Drive', 'Not quite hyperspeed, but getting close.', '(score.mods & 259 == 0) and 4 >= score.sr > 3', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (60, 'mania-skill-pass-4', 'Hyperspeed', 'Woah.', '(score.mods & 259 == 0) and 5 >= score.sr > 4', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (61, 'mania-skill-pass-5', 'Ever Onwards', 'Another challenge is just around the corner.', '(score.mods & 259 == 0) and 6 >= score.sr > 5', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (62, 'mania-skill-pass-6', 'Another Surpassed', 'Is there no limit to your skills?', '(score.mods & 259 == 0) and 7 >= score.sr > 6', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (63, 'mania-skill-pass-7', 'Extra Credit', 'See me after class.', '(score.mods & 259 == 0) and 8 >= score.sr > 7', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (64, 'mania-skill-pass-8', 'Maniac', 'There''s just no stopping you.', '(score.mods & 259 == 0) and 9 >= score.sr > 8', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (65, 'mania-skill-fc-1', 'Keystruck', 'The beginning of a new story', 'score.perfect and (score.mods & 259 == 0) and 2 >= score.sr > 1', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (66, 'mania-skill-fc-2', 'Keying In', 'Finding your groove.', 'score.perfect and 3 >= score.sr > 2', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (67, 'mania-skill-fc-3', 'Hyperflow', 'You can *feel* the rhythm.', 'score.perfect and 4 >= score.sr > 3', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (68, 'mania-skill-fc-4', 'Breakthrough', 'Many skills mastered, rolled into one.', 'score.perfect and 5 >= score.sr > 4', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (69, 'mania-skill-fc-5', 'Everything Extra', 'Giving your all is giving everything you have.', 'score.perfect and 6 >= score.sr > 5', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (70, 'mania-skill-fc-6', 'Level Breaker', 'Finesse beyond reason', 'score.perfect and 7 >= score.sr > 6', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (71, 'mania-skill-fc-7', 'Step Up', 'A precipice rarely seen.', 'score.perfect and 8 >= score.sr > 7', 3); -insert into achievements (`id`, `file`, `name`, `desc`, `cond`, `mode`) values (72, 'mania-skill-fc-8', 'Behind The Veil', 'Supernatural!', 'score.perfect and 9 >= score.sr > 8', 3); - -# v3.1.3 -alter table clans modify name varchar(16) charset utf8 not null; -alter table clans modify tag varchar(6) charset utf8 not null; -alter table achievements modify name varchar(128) charset utf8 not null; -alter table achievements modify `desc` varchar(256) charset utf8 not null; -alter table maps modify artist varchar(128) charset utf8 not null; -alter table maps modify title varchar(128) charset utf8 not null; -alter table maps modify version varchar(128) charset utf8 not null; -alter table maps modify creator varchar(19) charset utf8 not null comment 'not 100%% certain on len'; -alter table tourney_pools drop foreign key tourney_pools_users_id_fk; -alter table tourney_pool_maps drop foreign key tourney_pool_maps_tourney_pools_id_fk; -alter table stats drop foreign key stats_users_id_fk; -alter table ratings drop foreign key ratings_maps_md5_fk; -alter table ratings drop foreign key ratings_users_id_fk; -alter table logs modify `from` int not null comment 'both from and to are playerids'; - -# v3.1.9 -alter table scores_rx modify id bigint(20) unsigned auto_increment; -update scores_rx set id = id + (6148914691236517205 - 1); -select @max_rx := MAX(id) + 1 from scores_rx; -set @s = CONCAT('alter table scores_rx auto_increment = ', @max_rx); -prepare stmt from @s; -execute stmt; -deallocate PREPARE stmt; -alter table scores_ap modify id bigint(20) unsigned auto_increment; -update scores_ap set id = id + (12297829382473034410 - 1); -select @max_ap := MAX(id) + 1 from scores_ap; -set @s = CONCAT('alter table scores_ap auto_increment = ', @max_ap); -prepare stmt from @s; -execute stmt; -deallocate PREPARE stmt; -alter table performance_reports modify scoreid bigint(20) unsigned auto_increment; - -# v3.2.0 -create table map_requests -( - id int auto_increment - primary key, - map_id int not null, - player_id int not null, - datetime datetime not null, - active tinyint(1) not null -); - -# v3.2.1 -update scores_rx set id = id - 3074457345618258603; -update scores_ap set id = id - 6148914691236517206; - -# v3.2.2 -alter table maps add max_combo int not null after total_length; -alter table users change clan_rank clan_priv tinyint(1) default 0 not null; - -# v3.2.3 -alter table users add api_key char(36) default NULL null; -create unique index users_api_key_uindex on users (api_key); - -# v3.2.4 -update achievements set file = replace(file, 'ctb', 'fruits') where mode = 2; - -# v3.2.5 -update achievements set cond = '(score.mods & 1 == 0) and 1 <= score.sr < 2' where file in ('osu-skill-pass-1', 'taiko-skill-pass-1', 'fruits-skill-pass-1', 'mania-skill-pass-1'); -update achievements set cond = '(score.mods & 1 == 0) and 2 <= score.sr < 3' where file in ('osu-skill-pass-2', 'taiko-skill-pass-2', 'fruits-skill-pass-2', 'mania-skill-pass-2'); -update achievements set cond = '(score.mods & 1 == 0) and 3 <= score.sr < 4' where file in ('osu-skill-pass-3', 'taiko-skill-pass-3', 'fruits-skill-pass-3', 'mania-skill-pass-3'); -update achievements set cond = '(score.mods & 1 == 0) and 4 <= score.sr < 5' where file in ('osu-skill-pass-4', 'taiko-skill-pass-4', 'fruits-skill-pass-4', 'mania-skill-pass-4'); -update achievements set cond = '(score.mods & 1 == 0) and 5 <= score.sr < 6' where file in ('osu-skill-pass-5', 'taiko-skill-pass-5', 'fruits-skill-pass-5', 'mania-skill-pass-5'); -update achievements set cond = '(score.mods & 1 == 0) and 6 <= score.sr < 7' where file in ('osu-skill-pass-6', 'taiko-skill-pass-6', 'fruits-skill-pass-6', 'mania-skill-pass-6'); -update achievements set cond = '(score.mods & 1 == 0) and 7 <= score.sr < 8' where file in ('osu-skill-pass-7', 'taiko-skill-pass-7', 'fruits-skill-pass-7', 'mania-skill-pass-7'); -update achievements set cond = '(score.mods & 1 == 0) and 8 <= score.sr < 9' where file in ('osu-skill-pass-8', 'taiko-skill-pass-8', 'fruits-skill-pass-8', 'mania-skill-pass-8'); -update achievements set cond = '(score.mods & 1 == 0) and 9 <= score.sr < 10' where file = 'osu-skill-pass-9'; -update achievements set cond = '(score.mods & 1 == 0) and 10 <= score.sr < 11' where file = 'osu-skill-pass-10'; - -update achievements set cond = 'score.perfect and 1 <= score.sr < 2' where file in ('osu-skill-fc-1', 'taiko-skill-fc-1', 'fruits-skill-fc-1', 'mania-skill-fc-1'); -update achievements set cond = 'score.perfect and 2 <= score.sr < 3' where file in ('osu-skill-fc-2', 'taiko-skill-fc-2', 'fruits-skill-fc-2', 'mania-skill-fc-2'); -update achievements set cond = 'score.perfect and 3 <= score.sr < 4' where file in ('osu-skill-fc-3', 'taiko-skill-fc-3', 'fruits-skill-fc-3', 'mania-skill-fc-3'); -update achievements set cond = 'score.perfect and 4 <= score.sr < 5' where file in ('osu-skill-fc-4', 'taiko-skill-fc-4', 'fruits-skill-fc-4', 'mania-skill-fc-4'); -update achievements set cond = 'score.perfect and 5 <= score.sr < 6' where file in ('osu-skill-fc-5', 'taiko-skill-fc-5', 'fruits-skill-fc-5', 'mania-skill-fc-5'); -update achievements set cond = 'score.perfect and 6 <= score.sr < 7' where file in ('osu-skill-fc-6', 'taiko-skill-fc-6', 'fruits-skill-fc-6', 'mania-skill-fc-6'); -update achievements set cond = 'score.perfect and 7 <= score.sr < 8' where file in ('osu-skill-fc-7', 'taiko-skill-fc-7', 'fruits-skill-fc-7', 'mania-skill-fc-7'); -update achievements set cond = 'score.perfect and 8 <= score.sr < 9' where file in ('osu-skill-fc-8', 'taiko-skill-fc-8', 'fruits-skill-fc-8', 'mania-skill-fc-8'); -update achievements set cond = 'score.perfect and 9 <= score.sr < 10' where file = 'osu-skill-fc-9'; -update achievements set cond = 'score.perfect and 10 <= score.sr < 11' where file = 'osu-skill-fc-10'; - -update achievements set cond = '500 <= score.max_combo < 750' where file = 'osu-combo-500'; -update achievements set cond = '750 <= score.max_combo < 1000' where file = 'osu-combo-750'; -update achievements set cond = '1000 <= score.max_combo < 2000' where file = 'osu-combo-1000'; -update achievements set cond = '2000 <= score.max_combo' where file = 'osu-combo-2000'; - -# v3.2.6 -alter table stats change maxcombo_vn_std max_combo_vn_std int unsigned default 0 not null; -alter table stats change maxcombo_vn_taiko max_combo_vn_taiko int unsigned default 0 not null; -alter table stats change maxcombo_vn_catch max_combo_vn_catch int unsigned default 0 not null; -alter table stats change maxcombo_vn_mania max_combo_vn_mania int unsigned default 0 not null; -alter table stats change maxcombo_rx_std max_combo_rx_std int unsigned default 0 not null; -alter table stats change maxcombo_rx_taiko max_combo_rx_taiko int unsigned default 0 not null; -alter table stats change maxcombo_rx_catch max_combo_rx_catch int unsigned default 0 not null; -alter table stats change maxcombo_ap_std max_combo_ap_std int unsigned default 0 not null; - -# v3.2.7 -drop table if exists user_hashes; - -# v3.3.0 -rename table friendships to relationships; -alter table relationships add type enum('friend', 'block') not null; - -# v3.3.1 -create table ingame_logins -( - id int auto_increment - primary key, - userid int not null, - ip varchar(45) not null comment 'maxlen for ipv6', - osu_ver date not null, - osu_stream varchar(11) not null, - datetime datetime not null -); - -# v3.3.7 -update achievements set cond = CONCAT(cond, ' and mode_vn == 0') where mode = 0; -update achievements set cond = CONCAT(cond, ' and mode_vn == 1') where mode = 1; -update achievements set cond = CONCAT(cond, ' and mode_vn == 2') where mode = 2; -update achievements set cond = CONCAT(cond, ' and mode_vn == 3') where mode = 3; -alter table achievements drop column mode; - -# v3.3.8 -create table mapsets -( - server enum('osu!', 'gulag') default 'osu!' not null, - id int not null, - last_osuapi_check datetime default CURRENT_TIMESTAMP not null, - primary key (server, id), - constraint nmapsets_id_uindex - unique (id) -); - -# v3.4.1 -alter table maps add filename varchar(256) charset utf8 not null after creator; - -# v3.5.2 -alter table scores_vn add online_checksum char(32) not null; -alter table scores_rx add online_checksum char(32) not null; -alter table scores_ap add online_checksum char(32) not null; - -# v4.1.1 -alter table stats add total_hits int unsigned default 0 not null after max_combo; - -# v4.1.2 -alter table stats add replay_views int unsigned default 0 not null after total_hits; - -# v4.1.3 -alter table users add preferred_mode int default 0 not null after latest_activity; -alter table users add play_style int default 0 not null after preferred_mode; -alter table users add custom_badge_name varchar(16) charset utf8 null after play_style; -alter table users add custom_badge_icon varchar(64) null after custom_badge_name; -alter table users add userpage_content varchar(2048) charset utf8 null after custom_badge_icon; - -# v4.2.0 -# please refer to tools/migrate_v420 for further v4.2.0 migrations -update stats set mode = 8 where mode = 7; - -# v4.3.1 -alter table maps change server server enum('osu!', 'private') default 'osu!' not null; -alter table mapsets change server server enum('osu!', 'private') default 'osu!' not null; - -# v4.4.2 -insert into achievements (id, file, name, `desc`, cond) values (73, 'all-intro-suddendeath', 'Finality', 'High stakes, no regrets.', 'score.mods == 32'); -insert into achievements (id, file, name, `desc`, cond) values (74, 'all-intro-hidden', 'Blindsight', 'I can see just perfectly', 'score.mods & 8'); -insert into achievements (id, file, name, `desc`, cond) values (75, 'all-intro-perfect', 'Perfectionist', 'Accept nothing but the best.', 'score.mods & 16384'); -insert into achievements (id, file, name, `desc`, cond) values (76, 'all-intro-hardrock', 'Rock Around The Clock', "You can\'t stop the rock.", 'score.mods & 16'); -insert into achievements (id, file, name, `desc`, cond) values (77, 'all-intro-doubletime', 'Time And A Half', "Having a right ol\' time. One and a half of them, almost.", 'score.mods & 64'); -insert into achievements (id, file, name, `desc`, cond) values (78, 'all-intro-flashlight', 'Are You Afraid Of The Dark?', "Harder than it looks, probably because it\'s hard to look.", 'score.mods & 1024'); -insert into achievements (id, file, name, `desc`, cond) values (79, 'all-intro-easy', 'Dial It Right Back', 'Sometimes you just want to take it easy.', 'score.mods & 2'); -insert into achievements (id, file, name, `desc`, cond) values (80, 'all-intro-nofail', 'Risk Averse', 'Safety nets are fun!', 'score.mods & 1'); -insert into achievements (id, file, name, `desc`, cond) values (81, 'all-intro-nightcore', 'Sweet Rave Party', 'Founded in the fine tradition of changing things that were just fine as they were.', 'score.mods & 512'); -insert into achievements (id, file, name, `desc`, cond) values (82, 'all-intro-halftime', 'Slowboat', 'You got there. Eventually.', 'score.mods & 256'); -insert into achievements (id, file, name, `desc`, cond) values (83, 'all-intro-spunout', 'Burned Out', 'One cannot always spin to win.', 'score.mods & 4096'); - -# v4.4.3 -alter table favourites add created_at int default 0 not null; - -# v4.7.1 -lock tables maps write; -alter table maps drop primary key; -alter table maps add primary key (id); -alter table maps modify column server enum('osu!', 'private') not null default 'osu!' after id; -unlock tables; - -# v5.0.1 -create index channels_auto_join_index - on channels (auto_join); - -create index maps_set_id_index - on maps (set_id); -create index maps_status_index - on maps (status); -create index maps_filename_index - on maps (filename); -create index maps_plays_index - on maps (plays); -create index maps_mode_index - on maps (mode); -create index maps_frozen_index - on maps (frozen); - -create index scores_map_md5_index - on scores (map_md5); -create index scores_score_index - on scores (score); -create index scores_pp_index - on scores (pp); -create index scores_mods_index - on scores (mods); -create index scores_status_index - on scores (status); -create index scores_mode_index - on scores (mode); -create index scores_play_time_index - on scores (play_time); -create index scores_userid_index - on scores (userid); -create index scores_online_checksum_index - on scores (online_checksum); - -create index stats_mode_index - on stats (mode); -create index stats_pp_index - on stats (pp); -create index stats_tscore_index - on stats (tscore); -create index stats_rscore_index - on stats (rscore); - -create index tourney_pool_maps_mods_slot_index - on tourney_pool_maps (mods, slot); - -create index user_achievements_achid_index - on user_achievements (achid); -create index user_achievements_userid_index - on user_achievements (userid); - -create index users_priv_index - on users (priv); -create index users_clan_id_index - on users (clan_id); -create index users_clan_priv_index - on users (clan_priv); -create index users_country_index - on users (country); - -# v5.2.2 -create index scores_fetch_leaderboard_generic_index - on scores (map_md5, status, mode); diff --git a/migrations_old/sync_legacy_data.sql b/migrations_old/sync_legacy_data.sql deleted file mode 100644 index fca085e..0000000 --- a/migrations_old/sync_legacy_data.sql +++ /dev/null @@ -1,337 +0,0 @@ --- Lazer API 数据同步脚本 --- 从现有的 bancho.py 表结构同步数据到新的 lazer 专用表 --- 执行此脚本前请确保已执行 add_missing_fields.sql - --- ============================================ --- 同步用户基本资料数据 --- ============================================ - --- 同步用户扩展资料 -INSERT INTO lazer_user_profiles ( - user_id, - is_active, - is_bot, - is_deleted, - is_online, - is_supporter, - is_restricted, - session_verified, - has_supported, - pm_friends_only, - default_group, - last_visit, - join_date, - profile_colour, - profile_hue, - avatar_url, - cover_url, - discord, - twitter, - website, - title, - title_url, - interests, - location, - occupation, - playmode, - support_level, - max_blocks, - max_friends, - post_count, - page_html, - page_raw -) -SELECT - u.id as user_id, - -- 基本状态字段 (使用默认值,因为原表没有这些字段) - 1 as is_active, - CASE WHEN u.name = 'BanchoBot' THEN 1 ELSE 0 END as is_bot, - 0 as is_deleted, - 1 as is_online, - CASE WHEN u.donor_end > UNIX_TIMESTAMP() THEN 1 ELSE 0 END as is_supporter, - CASE WHEN (u.priv & 1) = 0 THEN 1 ELSE 0 END as is_restricted, - 0 as session_verified, - CASE WHEN u.donor_end > 0 THEN 1 ELSE 0 END as has_supported, - 0 as pm_friends_only, - - -- 基本资料字段 - 'default' as default_group, - CASE WHEN u.latest_activity > 0 THEN FROM_UNIXTIME(u.latest_activity) ELSE NULL END as last_visit, - CASE WHEN u.creation_time > 0 THEN FROM_UNIXTIME(u.creation_time) ELSE NULL END as join_date, - NULL as profile_colour, - NULL as profile_hue, - - -- 社交媒体和个人资料字段 (使用默认值) - CONCAT('https://a.ppy.sh/', u.id) as avatar_url, - CONCAT('https://assets.ppy.sh/user-profile-covers/banners/', u.id, '.jpg') as cover_url, - NULL as discord, - NULL as twitter, - NULL as website, - u.custom_badge_name as title, - NULL as title_url, - NULL as interests, - CASE WHEN u.country != 'xx' THEN u.country ELSE NULL END as location, - NULL as occupation, - - -- 游戏相关字段 - CASE u.preferred_mode - WHEN 0 THEN 'osu' - WHEN 1 THEN 'taiko' - WHEN 2 THEN 'fruits' - WHEN 3 THEN 'mania' - ELSE 'osu' - END as playmode, - CASE WHEN u.donor_end > UNIX_TIMESTAMP() THEN 1 ELSE 0 END as support_level, - 100 as max_blocks, - 500 as max_friends, - 0 as post_count, - - -- 页面内容 - u.userpage_content as page_html, - u.userpage_content as page_raw - -FROM users u -ON DUPLICATE KEY UPDATE - last_visit = VALUES(last_visit), - join_date = VALUES(join_date), - is_supporter = VALUES(is_supporter), - is_restricted = VALUES(is_restricted), - has_supported = VALUES(has_supported), - title = VALUES(title), - location = VALUES(location), - playmode = VALUES(playmode), - support_level = VALUES(support_level), - page_html = VALUES(page_html), - page_raw = VALUES(page_raw); - --- 同步用户国家信息 -INSERT INTO lazer_user_countries ( - user_id, - code, - name -) -SELECT - u.id as user_id, - UPPER(u.country) as code, - CASE UPPER(u.country) - WHEN 'CN' THEN 'China' - WHEN 'US' THEN 'United States' - WHEN 'JP' THEN 'Japan' - WHEN 'KR' THEN 'South Korea' - WHEN 'CA' THEN 'Canada' - WHEN 'GB' THEN 'United Kingdom' - WHEN 'DE' THEN 'Germany' - WHEN 'FR' THEN 'France' - WHEN 'AU' THEN 'Australia' - WHEN 'RU' THEN 'Russia' - ELSE 'Unknown' - END as name -FROM users u -WHERE u.country IS NOT NULL AND u.country != 'xx' -ON DUPLICATE KEY UPDATE - code = VALUES(code), - name = VALUES(name); - --- 同步用户 Kudosu (使用默认值) -INSERT INTO lazer_user_kudosu ( - user_id, - available, - total -) -SELECT - u.id as user_id, - 0 as available, - 0 as total -FROM users u -ON DUPLICATE KEY UPDATE - available = VALUES(available), - total = VALUES(total); - --- 同步用户统计计数 (使用默认值) -INSERT INTO lazer_user_counts ( - user_id, - beatmap_playcounts_count, - comments_count, - favourite_beatmapset_count, - follower_count, - graveyard_beatmapset_count, - guest_beatmapset_count, - loved_beatmapset_count, - mapping_follower_count, - nominated_beatmapset_count, - pending_beatmapset_count, - ranked_beatmapset_count, - ranked_and_approved_beatmapset_count, - unranked_beatmapset_count, - scores_best_count, - scores_first_count, - scores_pinned_count, - scores_recent_count -) -SELECT - u.id as user_id, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -FROM users u -ON DUPLICATE KEY UPDATE - user_id = VALUES(user_id); - --- ============================================ --- 同步游戏统计数据 --- ============================================ - --- 从 stats 表同步用户统计数据到 lazer_user_statistics -INSERT INTO lazer_user_statistics ( - user_id, - mode, - count_100, - count_300, - count_50, - count_miss, - level_current, - level_progress, - global_rank, - country_rank, - pp, - ranked_score, - hit_accuracy, - total_score, - total_hits, - maximum_combo, - play_count, - play_time, - replays_watched_by_others, - is_ranked, - grade_ss, - grade_ssh, - grade_s, - grade_sh, - grade_a -) -SELECT - s.id as user_id, - CASE s.mode - WHEN 0 THEN 'osu' - WHEN 1 THEN 'taiko' - WHEN 2 THEN 'fruits' - WHEN 3 THEN 'mania' - ELSE 'osu' - END as mode, - - -- 基本命中统计 - s.n100 as count_100, - s.n300 as count_300, - s.n50 as count_50, - s.nmiss as count_miss, - - -- 等级信息 - 1 as level_current, - 0 as level_progress, - - -- 排名信息 - NULL as global_rank, - NULL as country_rank, - - -- PP 和分数 - s.pp as pp, - s.rscore as ranked_score, - CASE WHEN (s.n300 + s.n100 + s.n50 + s.nmiss) > 0 - THEN ROUND((s.n300 * 300 + s.n100 * 100 + s.n50 * 50) / ((s.n300 + s.n100 + s.n50 + s.nmiss) * 300) * 100, 2) - ELSE 0.00 - END as hit_accuracy, - s.tscore as total_score, - (s.n300 + s.n100 + s.n50) as total_hits, - s.max_combo as maximum_combo, - - -- 游戏统计 - s.plays as play_count, - s.playtime as play_time, - 0 as replays_watched_by_others, - CASE WHEN s.pp > 0 THEN 1 ELSE 0 END as is_ranked, - - -- 成绩等级计数 - 0 as grade_ss, - 0 as grade_ssh, - 0 as grade_s, - 0 as grade_sh, - 0 as grade_a - -FROM stats s -WHERE EXISTS (SELECT 1 FROM users u WHERE u.id = s.id) -ON DUPLICATE KEY UPDATE - count_100 = VALUES(count_100), - count_300 = VALUES(count_300), - count_50 = VALUES(count_50), - count_miss = VALUES(count_miss), - pp = VALUES(pp), - ranked_score = VALUES(ranked_score), - hit_accuracy = VALUES(hit_accuracy), - total_score = VALUES(total_score), - total_hits = VALUES(total_hits), - maximum_combo = VALUES(maximum_combo), - play_count = VALUES(play_count), - play_time = VALUES(play_time), - is_ranked = VALUES(is_ranked); - --- ============================================ --- 同步用户成就数据 --- ============================================ - --- 从 user_achievements 表同步数据(如果存在的话) -INSERT IGNORE INTO lazer_user_achievements ( - user_id, - achievement_id, - achieved_at -) -SELECT - ua.userid as user_id, - ua.achid as achievement_id, - NOW() as achieved_at -- 使用当前时间作为获得时间 -FROM user_achievements ua -WHERE EXISTS (SELECT 1 FROM users u WHERE u.id = ua.userid); - --- ============================================ --- 创建基础 OAuth 令牌记录(如果需要的话) --- ============================================ - --- 注意: OAuth 令牌通常在用户登录时动态创建,这里不需要预先填充 - --- ============================================ --- 同步完成提示 --- ============================================ - --- 显示同步统计信息 -SELECT - 'lazer_user_profiles' as table_name, - COUNT(*) as synced_records -FROM lazer_user_profiles -UNION ALL -SELECT - 'lazer_user_countries' as table_name, - COUNT(*) as synced_records -FROM lazer_user_countries -UNION ALL -SELECT - 'lazer_user_statistics' as table_name, - COUNT(*) as synced_records -FROM lazer_user_statistics -UNION ALL -SELECT - 'lazer_user_achievements' as table_name, - COUNT(*) as synced_records -FROM lazer_user_achievements; - --- 显示一些样本数据 -SELECT - u.id, - u.name, - lup.is_supporter, - lup.playmode, - luc.code as country_code, - lus.pp, - lus.play_count -FROM users u -LEFT JOIN lazer_user_profiles lup ON u.id = lup.user_id -LEFT JOIN lazer_user_countries luc ON u.id = luc.user_id -LEFT JOIN lazer_user_statistics lus ON u.id = lus.user_id AND lus.mode = 'osu' -ORDER BY u.id -LIMIT 10; diff --git a/osu_api_example.py b/osu_api_example.py deleted file mode 100644 index 342d522..0000000 --- a/osu_api_example.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -import os - -import requests - -CLIENT_ID = os.environ.get("OSU_CLIENT_ID", "5") -CLIENT_SECRET = os.environ.get( - "OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" -) -API_URL = os.environ.get("OSU_API_URL", "https://osu.ppy.sh") - - -def authenticate(username: str, password: str): - """Authenticate via OAuth password flow and return the token dict.""" - url = f"{API_URL}/oauth/token" - data = { - "grant_type": "password", - "username": username, - "password": password, - "client_id": CLIENT_ID, - "client_secret": CLIENT_SECRET, - "scope": "*", - } - response = requests.post(url, data=data) - response.raise_for_status() - return response.json() - - -def refresh_token(refresh: str): - """Refresh the OAuth token.""" - url = f"{API_URL}/oauth/token" - data = { - "grant_type": "refresh_token", - "refresh_token": refresh, - "client_id": CLIENT_ID, - "client_secret": CLIENT_SECRET, - "scope": "*", - } - response = requests.post(url, data=data) - response.raise_for_status() - return response.json() - - -def get_current_user(access_token: str, ruleset: str = "osu"): - """Retrieve the authenticated user's data.""" - url = f"{API_URL}/api/v2/me/{ruleset}" - headers = {"Authorization": f"Bearer {access_token}"} - response = requests.get(url, headers=headers) - response.raise_for_status() - return response.json() - - -if __name__ == "__main__": - import getpass - - username = input("osu! username: ") - password = getpass.getpass() - - token = authenticate(username, password) - print("Access Token:", token["access_token"]) - user = get_current_user(token["access_token"]) - - print(user) diff --git a/quick_sync.py b/quick_sync.py deleted file mode 100644 index 9a0221e..0000000 --- a/quick_sync.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 -""" -简化的数据同步执行脚本 -直接使用项目配置执行数据同步 -""" - -from __future__ import annotations - -import os -import subprocess -from urllib.parse import urlparse - -from app.config import settings - - -def parse_database_url(): - """解析数据库 URL""" - url = urlparse(settings.DATABASE_URL) - return { - "host": url.hostname or "localhost", - "port": url.port or 3306, - "user": url.username or "root", - "password": url.password or "", - "database": url.path.lstrip("/") if url.path else "osu_api", - } - - -def run_sql_script(script_path: str): - """使用 mysql 命令行执行 SQL 脚本""" - if not os.path.exists(script_path): - print(f"错误: SQL 脚本不存在 - {script_path}") - return False - - # 解析数据库配置 - db_config = parse_database_url() - - # 构建 mysql 命令 - cmd = [ - "mysql", - f"--host={db_config['host']}", - f"--port={db_config['port']}", - f"--user={db_config['user']}", - db_config["database"], - ] - - # 添加密码(如果有的话) - if db_config["password"]: - cmd.insert(-1, f"--password={db_config['password']}") - - try: - print(f"执行 SQL 脚本: {script_path}") - with open(script_path, encoding="utf-8") as f: - result = subprocess.run( - cmd, stdin=f, capture_output=True, text=True, check=True - ) - - if result.stdout: - print("执行结果:") - print(result.stdout) - - print(f"✓ 成功执行: {script_path}") - return True - - except subprocess.CalledProcessError as e: - print(f"✗ 执行失败: {script_path}") - print(f"错误信息: {e.stderr}") - return False - except FileNotFoundError: - print("错误: 未找到 mysql 命令行工具") - print("请确保 MySQL 客户端已安装并添加到 PATH 环境变量中") - return False - - -def main(): - """主函数""" - print("Lazer API 快速数据同步") - print("=" * 40) - - db_config = parse_database_url() - print(f"数据库: {db_config['host']}:{db_config['port']}/{db_config['database']}") - print() - - # 确认是否继续 - print("这将执行以下操作:") - print("1. 创建 lazer 专用表结构") - print("2. 同步现有用户数据到新表") - print("3. 不会修改现有的原始表数据") - print() - - confirm = input("是否继续? (y/N): ").strip().lower() - if confirm != "y": - print("操作已取消") - return - - # 获取脚本路径 - script_dir = os.path.dirname(__file__) - migrations_dir = os.path.join(script_dir, "migrations_old") - - # 第一步: 创建表结构 - print("\n步骤 1: 创建 lazer 专用表结构...") - add_fields_script = os.path.join(migrations_dir, "add_missing_fields.sql") - if not run_sql_script(add_fields_script): - print("表结构创建失败,停止执行") - return - - # 第二步: 同步数据 - print("\n步骤 2: 同步历史数据...") - sync_script = os.path.join(migrations_dir, "sync_legacy_data.sql") - if not run_sql_script(sync_script): - print("数据同步失败") - return - - # 第三步: 添加缺失的字段 - print("\n步骤 3: 添加缺失的字段...") - add_rank_fields_script = os.path.join(migrations_dir, "add_lazer_rank_fields.sql") - if not run_sql_script(add_rank_fields_script): - print("添加字段失败") - return - - print("\n🎉 数据同步完成!") - print("\n现在您可以:") - print("1. 启动 Lazer API 服务器") - print("2. 使用现有用户账号登录") - print("3. 查看同步后的用户数据") - - -if __name__ == "__main__": - main() diff --git a/remove_ansi.py b/remove_ansi.py deleted file mode 100644 index 1720888..0000000 --- a/remove_ansi.py +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to remove ANSI escape codes from log files -""" - -from __future__ import annotations - -import re -import sys - - -def remove_ansi_codes(text): - """ - Remove ANSI escape codes from text - """ - # Regular expression to match ANSI escape codes - ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])") - return ansi_escape.sub("", text) - - -def process_log_file(input_file, output_file=None): - """ - Process log file and remove ANSI escape codes - """ - if output_file is None: - output_file = ( - input_file.replace(".log", "_clean.log") - if ".log" in input_file - else input_file + "_clean" - ) - - with open(input_file, "r", encoding="utf-8") as infile: - content = infile.read() - - # Remove ANSI escape codes - clean_content = remove_ansi_codes(content) - - with open(output_file, "w", encoding="utf-8") as outfile: - outfile.write(clean_content) - - print(f"Processed {input_file} -> {output_file}") - - -if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: python remove_ansi.py [output_file]") - sys.exit(1) - - input_file = sys.argv[1] - output_file = sys.argv[2] if len(sys.argv) > 2 else None - - process_log_file(input_file, output_file) diff --git a/sync_data.py b/sync_data.py deleted file mode 100644 index b69d7c8..0000000 --- a/sync_data.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env python3 -""" -Lazer API 数据同步脚本 -用于将现有的 bancho.py 数据同步到新的 lazer 专用表中 -""" - -from __future__ import annotations - -import logging -import os -import sys - -import pymysql - -# 配置日志 -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s", - handlers=[logging.FileHandler("data_sync.log"), logging.StreamHandler(sys.stdout)], -) - -logger = logging.getLogger(__name__) - - -class DatabaseSyncer: - def __init__(self, host: str, port: int, user: str, password: str, database: str): - """初始化数据库连接配置""" - self.host = host - self.port = port - self.user = user - self.password = password - self.database = database - self.connection = None - - def connect(self): - """连接到数据库""" - try: - self.connection = pymysql.connect( - host=self.host, - port=self.port, - user=self.user, - password=self.password, - database=self.database, - charset="utf8mb4", - autocommit=False, - ) - logger.info(f"成功连接到数据库 {self.database}") - except Exception as e: - logger.error(f"连接数据库失败: {e}") - raise - - def disconnect(self): - """断开数据库连接""" - if self.connection: - self.connection.close() - logger.info("数据库连接已关闭") - - def execute_sql_file(self, file_path: str): - """执行 SQL 文件""" - if not os.path.exists(file_path): - logger.error(f"SQL 文件不存在: {file_path}") - return False - - try: - with open(file_path, encoding="utf-8") as f: - sql_content = f.read() - - # 分割SQL语句(简单实现,按分号分割) - statements = [ - stmt.strip() for stmt in sql_content.split(";") if stmt.strip() - ] - - cursor = self.connection.cursor() - - for i, statement in enumerate(statements): - # 跳过注释和空语句 - if statement.startswith("--") or not statement: - continue - - try: - logger.info(f"执行第 {i + 1}/{len(statements)} 条SQL语句...") - cursor.execute(statement) - - # 如果是SELECT语句,显示结果 - if statement.strip().upper().startswith("SELECT"): - results = cursor.fetchall() - if results: - logger.info(f"查询结果: {results}") - - except Exception as e: - logger.error(f"执行SQL语句失败: {statement[:100]}...") - logger.error(f"错误信息: {e}") - # 继续执行其他语句 - continue - - self.connection.commit() - cursor.close() - logger.info(f"成功执行SQL文件: {file_path}") - return True - - except Exception as e: - logger.error(f"执行SQL文件失败: {e}") - if self.connection: - self.connection.rollback() - return False - - def check_tables_exist(self, tables: list) -> dict: - """检查表是否存在""" - results = {} - cursor = self.connection.cursor() - - for table in tables: - try: - cursor.execute(f"SHOW TABLES LIKE '{table}'") - exists = cursor.fetchone() is not None - results[table] = exists - logger.info(f"表 '{table}' {'存在' if exists else '不存在'}") - except Exception as e: - logger.error(f"检查表 '{table}' 时出错: {e}") - results[table] = False - - cursor.close() - return results - - def get_table_count(self, table: str) -> int: - """获取表的记录数""" - try: - cursor = self.connection.cursor() - cursor.execute(f"SELECT COUNT(*) FROM {table}") - result = cursor.fetchone() - count = result[0] if result else 0 - cursor.close() - return count - except Exception as e: - logger.error(f"获取表 '{table}' 记录数失败: {e}") - return -1 - - -def main(): - """主函数""" - print("Lazer API 数据同步工具") - print("=" * 50) - - # 数据库配置 - db_config = { - "host": input("数据库主机 [localhost]: ").strip() or "localhost", - "port": int(input("数据库端口 [3306]: ").strip() or "3306"), - "user": input("数据库用户名: ").strip(), - "password": input("数据库密码: ").strip(), - "database": input("数据库名称: ").strip(), - } - - syncer = DatabaseSyncer(**db_config) - - try: - # 连接数据库 - syncer.connect() - - # 检查必要的原始表是否存在 - required_tables = ["users", "stats"] - table_status = syncer.check_tables_exist(required_tables) - - missing_tables = [table for table, exists in table_status.items() if not exists] - if missing_tables: - logger.error(f"缺少必要的原始表: {missing_tables}") - return - - # 显示原始表的记录数 - for table in required_tables: - count = syncer.get_table_count(table) - logger.info(f"表 '{table}' 当前有 {count} 条记录") - - # 确认是否执行同步 - print("\n准备执行数据同步...") - print("这将会:") - print("1. 创建 lazer 专用表结构 (如果不存在)") - print("2. 从现有表同步数据到新表") - print("3. 不会修改或删除现有数据") - - confirm = input("\n是否继续? (y/N): ").strip().lower() - if confirm != "y": - print("操作已取消") - return - - # 执行表结构创建 - migrations_dir = os.path.join(os.path.dirname(__file__), "migrations_old") - - print("\n步骤 1: 创建表结构...") - add_fields_sql = os.path.join(migrations_dir, "add_missing_fields.sql") - if os.path.exists(add_fields_sql): - success = syncer.execute_sql_file(add_fields_sql) - if not success: - logger.error("创建表结构失败") - return - else: - logger.warning(f"表结构文件不存在: {add_fields_sql}") - - # 执行数据同步 - print("\n步骤 2: 同步数据...") - sync_sql = os.path.join(migrations_dir, "sync_legacy_data.sql") - if os.path.exists(sync_sql): - success = syncer.execute_sql_file(sync_sql) - if not success: - logger.error("数据同步失败") - return - else: - logger.error(f"同步脚本不存在: {sync_sql}") - return - - # 显示同步后的统计信息 - print("\n步骤 3: 同步完成统计...") - lazer_tables = [ - "lazer_user_profiles", - "lazer_user_countries", - "lazer_user_statistics", - "lazer_user_kudosu", - "lazer_user_counts", - ] - - for table in lazer_tables: - count = syncer.get_table_count(table) - if count >= 0: - logger.info(f"表 '{table}' 现在有 {count} 条记录") - - print("\n数据同步完成!") - - except KeyboardInterrupt: - print("\n\n操作被用户中断") - except Exception as e: - logger.error(f"同步过程中发生错误: {e}") - finally: - syncer.disconnect() - - -if __name__ == "__main__": - main() diff --git a/test_api.py b/test_api.py deleted file mode 100644 index c87ef5b..0000000 --- a/test_api.py +++ /dev/null @@ -1,256 +0,0 @@ -#!/usr/bin/env python3 -""" -测试 osu! API 模拟服务器的脚本 -""" - -from __future__ import annotations - -import os - -from dotenv import load_dotenv -import httpx as requests - -# 加载 .env 文件 -load_dotenv() - -CLIENT_ID = os.environ.get("OSU_CLIENT_ID", "5") -CLIENT_SECRET = os.environ.get( - "OSU_CLIENT_SECRET", "FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk" -) -API_URL = os.environ.get("OSU_API_URL", "http://localhost:8000") - - -def test_server_health(): - """测试服务器健康状态""" - try: - response = requests.get(f"{API_URL}/health") - if response.status_code == 200: - print("✅ 服务器健康检查通过") - return True - else: - print(f"❌ 服务器健康检查失败: {response.status_code}") - return False - except Exception as e: - print(f"❌ 无法连接到服务器: {e}") - return False - - -def authenticate(username: str, password: str): - """通过 OAuth 密码流进行身份验证并返回令牌字典""" - url = f"{API_URL}/oauth/token" - data = { - "grant_type": "password", - "username": username, - "password": password, - "client_id": CLIENT_ID, - "client_secret": CLIENT_SECRET, - "scope": "*", - } - - try: - response = requests.post(url, data=data) - if response.status_code == 200: - print("✅ 身份验证成功") - 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 refresh_token(refresh_token: str): - """刷新 OAuth 令牌""" - url = f"{API_URL}/oauth/token" - data = { - "grant_type": "refresh_token", - "refresh_token": refresh_token, - "client_id": CLIENT_ID, - "client_secret": CLIENT_SECRET, - "scope": "*", - } - - try: - response = requests.post(url, data=data) - if response.status_code == 200: - print("✅ 令牌刷新成功") - 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 get_current_user(access_token: str, ruleset: str = "osu"): - """获取认证用户的数据""" - url = f"{API_URL}/api/v2/me/{ruleset}" - headers = {"Authorization": f"Bearer {access_token}"} - - try: - response = requests.get(url, headers=headers) - if response.status_code == 200: - print(f"✅ 成功获取 {ruleset} 模式的用户数据") - 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 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 get_user_beatmap_score(access_token: str, beatmap_id: int, user_id: int): - """获取玩家成绩""" - url = f"{API_URL}/api/v2/beatmaps/{beatmap_id}/scores/users/{user_id}" - headers = {"Authorization": f"Bearer {access_token}"} - try: - response = requests.get(url, headers=headers) - if response.status_code == 200: - print(f"✅ 成功获取谱面 {beatmap_id} 中用户 {user_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 get_user_beatmap_score_all(access_token: str, beatmap_id: int, user_id: int): - """获取玩家成绩""" - url = f"{API_URL}/api/v2/beatmaps/{beatmap_id}/scores/users/{user_id}/all" - headers = {"Authorization": f"Bearer {access_token}"} - try: - response = requests.get(url, headers=headers) - if response.status_code == 200: - print(f"✅ 成功获取谱面 {beatmap_id} 中用户 {user_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") - - # 1. 测试服务器健康状态 - print("1. 检查服务器状态...") - if not test_server_health(): - print("请确保服务器正在运行: uvicorn main:app --reload") - return - - print() - - # 2. 获取用户凭据 - print("2. 用户身份验证...") - username = input("请输入用户名 (默认: Googujiang): ").strip() or "Googujiang" - - import getpass - - password = getpass.getpass("请输入密码 (默认: password123): ") or "password123" - - # 3. 身份验证 - print(f"\n3. 正在验证用户 '{username}'...") - token_data = authenticate(username, password) - if not token_data: - print("身份验证失败,请检查用户名和密码") - return - - print(f"访问令牌: {token_data['access_token']}") - print(f"刷新令牌: {token_data['refresh_token']}") - print(f"令牌有效期: {token_data['expires_in']} 秒") - - # 4. 获取用户数据 - print("\n4. 获取用户数据...") - for ruleset in ["osu", "taiko", "fruits", "mania"]: - print(f"\n--- {ruleset.upper()} 模式 ---") - user_data = get_current_user(token_data["access_token"], ruleset) - if user_data: - print(f"用户名: {user_data['username']}") - print(f"国家: {user_data['country']['name']} ({user_data['country_code']})") - print(f"全球排名: {user_data['statistics']['global_rank']}") - print(f"PP: {user_data['statistics']['pp']}") - print(f"游戏次数: {user_data['statistics']['play_count']}") - print(f"命中精度: {user_data['statistics']['hit_accuracy']:.2f}%") - - # 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']}\n") - else: - print("用户在该谱面没有成绩记录\n") - - # 5a. 测试谱面指定用户成绩 - user_score = get_user_beatmap_score(token_data["access_token"], 1, 1) - if user_score: - print(f"用户成绩ID:{user_score['score']['id']}") - print(f"此成绩acc:{user_score['score']['accuracy']}") - print(f"总分:{user_score['score']['classic_total_score']}\n") - else: - print("该用户在此谱面没有记录\n") - - # 5b. 测试谱面指定用户成绩 - user_score_all = get_user_beatmap_score_all(token_data["access_token"], 1, 1) - if user_score_all: - index = 1 - for score in user_score_all: - print(f"第{index}个成绩:") - print(f"用户成绩ID:{score['id']}") - print(f"此成绩acc:{score['accuracy']}") - print(f"总分:{score['classic_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. 使用新令牌获取用户数据...") - user_data = get_current_user(new_token_data["access_token"]) - if user_data: - print(f"✅ 新令牌有效,用户: {user_data['username']}") - - print("\n=== 测试完成 ===") - - -if __name__ == "__main__": - main() diff --git a/test_lazer.py b/test_lazer.py deleted file mode 100644 index 627325d..0000000 --- a/test_lazer.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python3 -""" -Lazer API 系统测试脚本 -验证新的 lazer 表支持是否正常工作 -""" - -from __future__ import annotations - -import os -import sys - -sys.path.append(os.path.dirname(os.path.dirname(__file__))) - -from app.database import User -from app.dependencies.database import engine -from app.utils import convert_db_user_to_api_user - -from sqlmodel import select -from sqlmodel.ext.asyncio.session import AsyncSession - - -async def test_lazer_tables(): - """测试 lazer 表的基本功能""" - print("测试 Lazer API 表支持...") - - async with AsyncSession(engine) as session: - async with session.begin(): - try: - # 测试查询用户 - statement = select(User) - result = await session.execute(statement) - user = result.scalars().first() - if not user: - print("❌ 没有找到用户,请先同步数据") - return False - - print(f"✓ 找到用户: {user.name} (ID: {user.id})") - - # 测试 lazer 资料 - if user.lazer_profile: - print( - f"✓ 用户有 lazer 资料: 支持者={user.lazer_profile.is_supporter}" - ) - else: - print("⚠ 用户没有 lazer 资料,将使用默认值") - - # 测试 lazer 统计 - osu_stats = None - for stat in user.lazer_statistics: - if stat.mode == "osu": - osu_stats = stat - break - - if osu_stats: - print( - f"✓ 用户有 osu! 统计: PP={osu_stats.pp}, " - f"游戏次数={osu_stats.play_count}" - ) - else: - print("⚠ 用户没有 osu! 统计,将使用默认值") - - # 测试转换为 API 格式 - api_user = convert_db_user_to_api_user(user, "osu") - print("✓ 成功转换为 API 用户格式") - print(f" - 用户名: {api_user.username}") - print(f" - 国家: {api_user.country_code}") - print(f" - PP: {api_user.statistics.pp}") - print(f" - 是否支持者: {api_user.is_supporter}") - - return True - - except Exception as e: - print(f"❌ 测试失败: {e}") - import traceback - - traceback.print_exc() - return False - - -async def test_authentication(): - """测试认证功能""" - print("\n测试认证功能...") - - async with AsyncSession(engine) as session: - async with session.begin(): - try: - # 尝试认证第一个用户 - statement = select(User) - result = await session.execute(statement) - user = result.scalars().first() - if not user: - print("❌ 没有用户进行认证测试") - return False - - print(f"✓ 测试用户: {user.name}") - print("⚠ 注意: 实际密码认证需要正确的密码") - - return True - - except Exception as e: - print(f"❌ 认证测试失败: {e}") - return False - - -async def main(): - """主测试函数""" - print("Lazer API 系统测试") - print("=" * 40) - - # 测试表连接 - success1 = await test_lazer_tables() - - # 测试认证 - success2 = await test_authentication() - - print("\n" + "=" * 40) - if success1 and success2: - print("🎉 所有测试通过!") - print("\n现在可以:") - print("1. 启动 API 服务器: python main.py") - print("2. 测试 OAuth 认证") - print("3. 调用 /api/v2/me/osu 获取用户信息") - else: - print("❌ 测试失败,请检查:") - print("1. 数据库连接是否正常") - print("2. 是否已运行数据同步脚本") - print("3. lazer 表是否正确创建") - - -if __name__ == "__main__": - import asyncio - - asyncio.run(main()) diff --git a/test_password.py b/test_password.py deleted file mode 100644 index c0aa3cd..0000000 --- a/test_password.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -""" -测试密码哈希和验证逻辑 -""" - -from __future__ import annotations - -import hashlib - -from app.auth import bcrypt_cache, get_password_hash, verify_password_legacy - - -def test_password_logic(): - """测试密码逻辑""" - print("=== 测试密码哈希和验证逻辑 ===\n") - - # 测试密码 - password = "password123" - print(f"原始密码: {password}") - - # 1. 生成哈希 - print("\n1. 生成密码哈希...") - hashed = get_password_hash(password) - print(f"bcrypt 哈希: {hashed}") - - # 2. 验证密码 - print("\n2. 验证密码...") - is_valid = verify_password_legacy(password, hashed) - print(f"验证结果: {'✅ 成功' if is_valid else '❌ 失败'}") - - # 3. 测试错误密码 - print("\n3. 测试错误密码...") - wrong_password = "wrongpassword" - is_valid_wrong = verify_password_legacy(wrong_password, hashed) - print(f"错误密码验证结果: {'❌ 不应该成功' if is_valid_wrong else '✅ 正确拒绝'}") - - # 4. 测试缓存 - print("\n4. 缓存状态:") - print(f"缓存中的条目数: {len(bcrypt_cache)}") - if hashed in bcrypt_cache: - print(f"缓存的 MD5: {bcrypt_cache[hashed]}") - expected_md5 = hashlib.md5(password.encode()).hexdigest().encode() - print(f"期望的 MD5: {expected_md5}") - print(f"缓存匹配: {'✅' if bcrypt_cache[hashed] == expected_md5 else '❌'}") - - # 5. 再次验证(应该使用缓存) - print("\n5. 再次验证(使用缓存)...") - is_valid_cached = verify_password_legacy(password, hashed) - print(f"缓存验证结果: {'✅ 成功' if is_valid_cached else '❌ 失败'}") - - print("\n=== 测试完成 ===") - - -if __name__ == "__main__": - test_password_logic()