feat(beatmap): 添加谱面用户标签功能 (#25)

* feat(tags): 添加 beatmap tags 相关功能

- 新增 BeatmapTags 模型类,用于表示 beatmap 的标签信息
- 实现加载标签数据、根据 ID 获取标签、获取所有标签等功能

* feat(database): 新增 BeatmapTagVote 数据库模型和迁移脚本

* fix(database): 修改 BeatmapTagVote 模型并创建新表

- 将 BeatmapTagVote 模型的表名从 "beatmap_tag_votes" 改为 "beatmap_tags"
- 创建新的数据库迁移文件以替换错误的原迁移文件
- 删除错误的迁移文件 "4a827ddba235_add_table_beatmap_tags.py"

* feat(tags): 添加用户标签功能

- 在 BeatmapResp 类中添加了 top_tag_ids 和 current_user_tag_ids 字段
- 新增了 /tags 相关的路由,包括获取所有标签和投票/取消投票功能
- 实现了标签投票和取消投票的数据库操作

* fix(tags): 修复标签投票查询和返回过程中的逻辑问题

- 修复 BeatmapResp 类中 current_user_tag_ids 字段的查询逻辑
- 优化 vote_beatmap_tags 函数中的标签验证过程

* fix(tags): add suggested changes from reviews

- 在 BeatmapResp 中添加 top_tag_ids 和 current_user_tag_ids 字段
- 实现用户标签投票功能,包括检查用户是否有资格投票
- 优化标签数据的加载方式
- 调整标签相关路由,增加路径参数描述

* fix(tags): apply changes from review

* fix(tag): apply changes from review suggests

- 更新标签接口文档,统一参数描述
- 修改标签投票接口状态码为 204
- 优化标签投票接口的用户认证方式
- 改进标签相关错误处理,使用更友好的错误信息

* fix(tag): use client authorization

* chore(linter): auto fix by pre-commit hooks

---------

Co-authored-by: MingxuanGame <MingxuanGame@outlook.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
陈晋瑭
2025-08-30 16:23:59 +08:00
committed by GitHub
parent d38cf12826
commit 6c2e88c485
7 changed files with 264 additions and 0 deletions

47
app/models/tags.py Normal file
View File

@@ -0,0 +1,47 @@
from __future__ import annotations
import json
from app.log import logger
from app.path import STATIC_DIR
from pydantic import BaseModel
class BeatmapTags(BaseModel):
id: int
name: str = ""
description: str = ""
ruleset_id: int | None = None
ALL_TAGS: dict[int, BeatmapTags] = {}
def load_tags() -> None:
if len(ALL_TAGS) > 0:
return
if not (STATIC_DIR / "beatmap_tags.json").exists():
logger.warning("beatmap tags description file does not exist, using no tags")
return
tags_list = json.loads((STATIC_DIR / "beatmap_tags.json").read_text())
for tag in tags_list:
if tag["id"] in ALL_TAGS:
logger.error("find duplicated beatmap tag id")
logger.info(f"tag {ALL_TAGS[tag['id']].name} and tag {tag['name']} have the same tag id")
raise ValueError("duplicated tag id found")
ALL_TAGS[tag["id"]] = BeatmapTags.model_validate(tag)
def get_tag_by_id(id: int) -> BeatmapTags:
load_tags()
tag = ALL_TAGS.get(id)
if tag is None:
logger.error(f"tag id {id} not found")
raise ValueError("tag id not found")
return tag
def get_all_tags() -> list[BeatmapTags]:
load_tags()
return list(ALL_TAGS.values())