feat: 完成源晶权限与经验系统并优化 me/admin 交互
这个提交包含在:
@@ -6,10 +6,35 @@
|
||||
|
||||
## 通用约定
|
||||
|
||||
- 鉴权头:`Authorization: Bearer <token>`
|
||||
- 鉴权头(二选一):
|
||||
- `Authorization: Bearer <token>`(推荐)
|
||||
- `Authorization: Basic <base64(username:password)>`(第三方直连更方便)
|
||||
- 成功响应:`{ "ok": true, "data": ... }`(Auth 接口除外)
|
||||
- 失败响应:`{ "ok": false, "error": "..." }`
|
||||
|
||||
### 第三方接入快速示例
|
||||
|
||||
1) 登录拿 token(Bearer 方式)
|
||||
```bash
|
||||
curl -X POST 'https://csp.hao.work/admin139/api/v1/auth/login' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"username":"alice","password":"password123"}'
|
||||
```
|
||||
|
||||
2) Bearer 调用
|
||||
```bash
|
||||
curl 'https://csp.hao.work/admin139/api/v1/me' \
|
||||
-H 'Authorization: Bearer <token>'
|
||||
```
|
||||
|
||||
3) Basic 直接调用
|
||||
```bash
|
||||
curl 'https://csp.hao.work/admin139/api/v1/me' \
|
||||
-H 'Authorization: Basic YWxpY2U6cGFzc3dvcmQxMjM='
|
||||
```
|
||||
|
||||
> `YWxpY2U6cGFzc3dvcmQxMjM=` 是 `alice:password123` 的 Base64。
|
||||
|
||||
---
|
||||
|
||||
## 1) Auth
|
||||
@@ -65,7 +90,7 @@
|
||||
```
|
||||
- `contest_id` 可选;若提交到比赛,需已报名且比赛进行中。
|
||||
|
||||
### `GET /submissions?user_id=&problem_id=&contest_id=&page=&page_size=`
|
||||
### `GET /submissions?user_id=&problem_id=&contest_id=&created_from=&created_to=&page=&page_size=`
|
||||
返回提交列表。
|
||||
|
||||
### `GET /submissions/:id`
|
||||
@@ -120,6 +145,24 @@
|
||||
### `GET /kb/articles/:slug`
|
||||
返回文章详情与关联题目。
|
||||
|
||||
### `GET /kb/articles/:slug/claims`(需鉴权)
|
||||
返回当前用户在该文章下已领取知识点和累计积分。
|
||||
|
||||
### `POST /kb/articles/:slug/claim`(需鉴权)
|
||||
请求:
|
||||
```json
|
||||
{ "knowledge_key": "cpp14-io-01" }
|
||||
```
|
||||
说明:
|
||||
- 有前置依赖的知识点,若前置未完成会返回 400。
|
||||
- 同一知识点不可重复领取积分。
|
||||
|
||||
### `GET /kb/weekly-plan`(需鉴权)
|
||||
返回本周自动生成的学习任务(含完成度、奖励汇总)。
|
||||
|
||||
### `POST /kb/weekly-bonus/claim`(需鉴权)
|
||||
领取本周任务 100% 完成奖励;未达 100% 返回 400。
|
||||
|
||||
---
|
||||
|
||||
## 8) 题库导入任务(PDF + LLM)
|
||||
@@ -157,3 +200,53 @@
|
||||
|
||||
### `GET /backend/logs?limit=100`
|
||||
返回最近题解生成任务日志(按任务 ID 倒序),并包含当前排队任务数 `pending_jobs`。
|
||||
|
||||
### `GET /backend/db-lock-guard/status`(需管理员鉴权)
|
||||
返回 SQLite 锁守护运行状态,字段包含:
|
||||
- `enabled` / `started`:守护是否启用、是否已启动
|
||||
- `interval_sec` / `probe_busy_timeout_ms`:探测间隔与超时
|
||||
- `busy_streak` / `busy_streak_trigger`:当前连续锁冲突计数与触发阈值
|
||||
- `last_probe_at` / `last_probe_rc` / `last_probe_error`:最近探测结果
|
||||
- `last_repair_at` / `repair_count`:最近一次自愈时间与累计自愈次数
|
||||
|
||||
---
|
||||
|
||||
## 10) 网站爬虫列表(管理员)
|
||||
|
||||
### `GET /admin/crawlers?status=&limit=`
|
||||
返回爬虫目标列表(按最新倒序)。
|
||||
|
||||
### `POST /admin/crawlers`
|
||||
手动新增爬虫目标。请求体示例:
|
||||
```json
|
||||
{ "url": "https://example.com" }
|
||||
```
|
||||
|
||||
### `POST /admin/crawlers/:id/queue`
|
||||
将目标重新入队,触发“规则生成 -> 自动测试 -> 自动运行”流程。
|
||||
|
||||
### `GET /admin/crawlers/:id/runs?limit=20`
|
||||
查看指定目标的运行记录。
|
||||
|
||||
### `GET /backend/crawler-guard/status`(需管理员鉴权)
|
||||
返回爬虫守护进程状态(是否启用、是否运行、处理统计、最近错误等)。
|
||||
- `active_requeue_interval_sec` 表示活跃目标的周期重跑间隔(秒,默认 43200 即 12 小时)。
|
||||
|
||||
> 飞书群内 `@机器人` 文本如果包含 URL,也会自动写入爬虫目标列表并触发守护流程。
|
||||
|
||||
---
|
||||
|
||||
## 11) Lark 机器人事件回调
|
||||
|
||||
### `POST /lark/events`
|
||||
用于飞书(Lark)事件订阅回调,支持:
|
||||
- URL 验证:请求体带 `challenge` 时回传 `{ "challenge": "..." }`
|
||||
- 消息事件:处理 `im.message.receive_v1` 文本消息并异步回复
|
||||
|
||||
环境变量(后端):
|
||||
- `CSP_LARK_BOT_ENABLED=true`:是否启用机器人
|
||||
- `CSP_LARK_VERIFICATION_TOKEN=...`:事件回调 token(可选,建议配置)
|
||||
- `CSP_LARK_APP_ID=...` / `CSP_LARK_APP_SECRET=...`:飞书应用凭据
|
||||
- `CSP_LARK_OPEN_BASE_URL=https://open.feishu.cn`:飞书 OpenAPI 域名
|
||||
- `CSP_LARK_LLM_API_URL=...` / `CSP_LARK_LLM_API_KEY=...` / `CSP_LARK_LLM_MODEL=...`:对话模型配置
|
||||
- 可选:`CSP_LARK_LLM_SYSTEM_PROMPT`、`CSP_LARK_MEMORY_TURNS`、`CSP_LARK_MAX_REPLY_CHARS`
|
||||
|
||||
@@ -76,8 +76,55 @@ OI_IMPORT_WORKERS=3
|
||||
OI_IMPORT_CLEAR_EXISTING=true
|
||||
OI_IMPORT_CLEAR_SOURCE_PREFIX=winterant/oi
|
||||
OI_IMPORT_CLEAR_ALL_PROBLEMS=false
|
||||
|
||||
# SQLite 锁守护(定时探测 + 自愈)
|
||||
CSP_SQLITE_BUSY_TIMEOUT_MS=15000
|
||||
CSP_DB_LOCK_GUARD_ENABLED=true
|
||||
CSP_DB_LOCK_GUARD_INTERVAL_SEC=20
|
||||
CSP_DB_LOCK_GUARD_PROBE_TIMEOUT_MS=2000
|
||||
CSP_DB_LOCK_GUARD_BUSY_STREAK=3
|
||||
|
||||
# Lark 机器人(事件回调 + 对话)
|
||||
CSP_LARK_BOT_ENABLED=false
|
||||
CSP_LARK_VERIFICATION_TOKEN=
|
||||
CSP_LARK_APP_ID=
|
||||
CSP_LARK_APP_SECRET=
|
||||
CSP_LARK_OPEN_BASE_URL=https://open.feishu.cn
|
||||
CSP_LARK_LLM_API_URL=
|
||||
CSP_LARK_LLM_API_KEY=
|
||||
CSP_LARK_LLM_MODEL=qwen3-max
|
||||
CSP_LARK_LLM_SYSTEM_PROMPT=你是 CSP Quest World 的编程助教。请用简洁中文回答,先给结论,再给步骤。
|
||||
CSP_LARK_LLM_TIMEOUT_SEC=30
|
||||
CSP_LARK_API_TIMEOUT_SEC=15
|
||||
CSP_LARK_MEMORY_TURNS=6
|
||||
CSP_LARK_MAX_REPLY_CHARS=1200
|
||||
|
||||
# 网站爬虫守护(URL 入库后自动:生成规则 -> 测试 -> 运行)
|
||||
CSP_CRAWLER_ENABLED=true
|
||||
CSP_CRAWLER_INTERVAL_SEC=15
|
||||
CSP_CRAWLER_REQUEUE_INTERVAL_SEC=43200
|
||||
CSP_CRAWLER_FETCH_TIMEOUT_SEC=20
|
||||
CSP_CRAWLER_SCRIPT_DIR=/data/crawlers
|
||||
CSP_CRAWLER_LLM_API_URL=https://one.hao.work/v1/chat/completions
|
||||
CSP_CRAWLER_LLM_API_KEY=替换为你的Key
|
||||
CSP_CRAWLER_LLM_MODEL=qwen3-max
|
||||
CSP_CRAWLER_LLM_TIMEOUT_SEC=30
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `CSP_SQLITE_BUSY_TIMEOUT_MS`:主连接遇到锁时的等待时间(毫秒)。
|
||||
- `CSP_DB_LOCK_GUARD_ENABLED`:是否启用定时守护。
|
||||
- `CSP_DB_LOCK_GUARD_INTERVAL_SEC`:守护探测间隔(秒)。
|
||||
- `CSP_DB_LOCK_GUARD_PROBE_TIMEOUT_MS`:守护探测连接的 busy timeout(毫秒)。
|
||||
- `CSP_DB_LOCK_GUARD_BUSY_STREAK`:连续探测到 busy/locked 达到阈值后触发一次自愈(WAL checkpoint + optimize)。
|
||||
- `CSP_LARK_BOT_ENABLED`:是否启用 Lark 对话机器人回调处理。
|
||||
- `CSP_LARK_VERIFICATION_TOKEN`:Lark 事件回调 token(建议配置)。
|
||||
- `CSP_LARK_APP_ID/CSP_LARK_APP_SECRET`:Lark 应用凭据。
|
||||
- `CSP_LARK_LLM_*`:机器人对话调用的模型配置。
|
||||
- `CSP_CRAWLER_*`:网站爬虫守护配置(URL 入库后自动生成规则/测试/运行)。
|
||||
- `CSP_CRAWLER_REQUEUE_INTERVAL_SEC`:已激活目标再次入队执行的周期(秒,`43200`=12小时,`0`=关闭周期重跑)。
|
||||
|
||||
## 5. 故障排查
|
||||
|
||||
### 5.1 无法访问 7888
|
||||
|
||||
97
docs/知识库重塑与游戏化规划.md
普通文件
97
docs/知识库重塑与游戏化规划.md
普通文件
@@ -0,0 +1,97 @@
|
||||
# 知识库重塑与游戏化规划(CSP 平台)
|
||||
|
||||
## 1. 重塑目标
|
||||
- 建立“可学习、可打卡、可成长”的知识库系统,不再只是文章列表。
|
||||
- 形成四条核心技能线:
|
||||
- C++14 技能树(竞赛编码主线)
|
||||
- GitHub 协作技能树(团队工程主线)
|
||||
- Linux 服务器技能树(部署运维主线)
|
||||
- 计算机基础技能树(底层认知主线)
|
||||
- 将“知识点学习”直接转化为积分成长,形成闭环:学习 -> 打卡 -> 得分 -> 排行与成长反馈。
|
||||
|
||||
## 2. 内容架构
|
||||
### 2.1 主线知识文章(已落地)
|
||||
- `cpp14-skill-tree`
|
||||
- `github-collaboration-basics`
|
||||
- `linux-server-basics`
|
||||
- `computer-fundamentals-for-oi`
|
||||
|
||||
### 2.2 每篇文章的知识点模型
|
||||
- 每篇文章附带一组 `skill_points`:
|
||||
- `key`: 唯一知识点 ID
|
||||
- `title`: 知识点标题
|
||||
- `description`: 可执行的学习目标
|
||||
- `difficulty`: bronze/silver/gold
|
||||
- `reward`: 领取奖励分值
|
||||
|
||||
### 2.3 文章与题目联动
|
||||
- 保留 `kb_article_links`,把知识点和题目联起来。
|
||||
- 在 KB 列表中提供“做相关任务”跳转到题库搜索。
|
||||
|
||||
## 3. 游戏化机制
|
||||
### 3.1 积分获取
|
||||
- 用户可对每个知识点打卡领取奖励。
|
||||
- 领取规则:`user + article + knowledge_key` 唯一,不可重复刷分。
|
||||
- 奖励实时写入用户 `rating`。
|
||||
|
||||
### 3.2 数据表设计
|
||||
- 新增表:`kb_knowledge_claims`
|
||||
- `user_id`
|
||||
- `article_id`
|
||||
- `knowledge_key`
|
||||
- `reward`
|
||||
- `created_at`
|
||||
- 唯一约束:`UNIQUE(user_id, article_id, knowledge_key)`
|
||||
|
||||
### 3.3 成长展示
|
||||
- 文章详情页展示:
|
||||
- 技能点清单
|
||||
- 已领取数量
|
||||
- 已领取总积分
|
||||
- 单点“领取奖励”按钮与状态
|
||||
- 积分流水新增 `kb_skill` 类型,进入个人成长历史。
|
||||
|
||||
## 4. 交互设计
|
||||
### 4.1 KB 列表页
|
||||
- 支持关键词搜索。
|
||||
- 增加快捷筛选按钮:`C++14`、`GitHub`、`Linux`、`计算机基础`。
|
||||
- 分类分组:路线图、C++、CSP-J、CSP-S、GitHub、Linux、计算机基础、其他。
|
||||
|
||||
### 4.2 KB 详情页
|
||||
- 文章内容区
|
||||
- 技能打卡区(奖励领取)
|
||||
- 关联题目区(学练结合)
|
||||
|
||||
## 5. 版本规划(建议)
|
||||
### Phase A(当前已实现)
|
||||
- 重构四条核心文章
|
||||
- 技能点打卡与积分领取
|
||||
- 积分流水接入
|
||||
- KB 列表筛选与分类增强
|
||||
|
||||
### Phase B(下一步)
|
||||
- 技能点前置依赖(先修解锁)
|
||||
- 每周学习任务(自动生成)
|
||||
- 学习路径推荐(根据已领取点与错题)
|
||||
- 章节徽章(铜/银/金)
|
||||
|
||||
### Phase C(进阶)
|
||||
- 班级/战队学习排行
|
||||
- 学习挑战赛(限时技能闯关)
|
||||
- 知识点掌握度雷达图
|
||||
- AI 学习教练(按薄弱点推送下一步)
|
||||
|
||||
## 6. 运营指标(建议)
|
||||
- 日活学习人数
|
||||
- 人均领取知识点数
|
||||
- 文章完成率(领取数 / 可领取数)
|
||||
- 学完知识后去做题转化率
|
||||
- 学习后 AC 提升率
|
||||
|
||||
## 7. 风险与控制
|
||||
- 风险:刷接口刷分。
|
||||
- 控制:唯一约束 + 服务端验证技能点 key。
|
||||
- 风险:内容过长难消化。
|
||||
- 控制:拆分为技能点任务和周计划。
|
||||
- 风险:学习与做题割裂。
|
||||
- 控制:每篇文章都提供相关题目入口。
|
||||
101
docs/第三方REST接入指南.md
普通文件
101
docs/第三方REST接入指南.md
普通文件
@@ -0,0 +1,101 @@
|
||||
# CSP Quest World 第三方 REST 接入指南
|
||||
|
||||
本文档用于第三方系统(脚本、自动化平台、企业内部系统)快速接入 CSP Quest World 的 REST API。
|
||||
|
||||
## 1. 基础信息
|
||||
|
||||
- 线上基础地址:`https://csp.hao.work/admin139/api/v1`
|
||||
- 文档入口(Swagger):`https://csp.hao.work/api-docs`
|
||||
- OpenAPI JSON:`https://csp.hao.work/admin139/api/openapi.json`
|
||||
- 数据格式:`application/json`
|
||||
|
||||
## 2. 鉴权方式
|
||||
|
||||
受保护接口支持两种方式,任选其一:
|
||||
|
||||
1. Bearer Token(推荐)
|
||||
- 先调用 `/auth/login` 获取 `token`
|
||||
- 请求头带上:`Authorization: Bearer <token>`
|
||||
|
||||
2. Basic 账号密码(适合第三方直连)
|
||||
- 请求头带上:`Authorization: Basic <base64(username:password)>`
|
||||
- 示例:`alice:password123` -> `YWxpY2U6cGFzc3dvcmQxMjM=`
|
||||
|
||||
说明:
|
||||
- 两种方式都可访问全部 REST 接口。
|
||||
- 管理员接口仍需管理员账号(如 `admin`)才能通过权限校验。
|
||||
|
||||
## 3. 快速调用示例
|
||||
|
||||
### 3.1 登录获取 Token
|
||||
|
||||
```bash
|
||||
curl -X POST 'https://csp.hao.work/admin139/api/v1/auth/login' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"username":"alice","password":"password123"}'
|
||||
```
|
||||
|
||||
### 3.2 使用 Bearer 调用
|
||||
|
||||
```bash
|
||||
curl 'https://csp.hao.work/admin139/api/v1/me' \
|
||||
-H 'Authorization: Bearer <token>'
|
||||
```
|
||||
|
||||
### 3.3 使用 Basic 调用
|
||||
|
||||
```bash
|
||||
curl 'https://csp.hao.work/admin139/api/v1/me' \
|
||||
-H 'Authorization: Basic YWxpY2U6cGFzc3dvcmQxMjM='
|
||||
```
|
||||
|
||||
## 4. Python 示例(requests)
|
||||
|
||||
```python
|
||||
import base64
|
||||
import requests
|
||||
|
||||
BASE = "https://csp.hao.work/admin139/api/v1"
|
||||
username = "alice"
|
||||
password = "password123"
|
||||
|
||||
basic = base64.b64encode(f"{username}:{password}".encode("utf-8")).decode("utf-8")
|
||||
headers = {"Authorization": f"Basic {basic}"}
|
||||
|
||||
resp = requests.get(f"{BASE}/me", headers=headers, timeout=15)
|
||||
resp.raise_for_status()
|
||||
print(resp.json())
|
||||
```
|
||||
|
||||
## 5. 响应约定
|
||||
|
||||
- 成功:`{ "ok": true, "data": ... }`(Auth 接口除外)
|
||||
- 失败:`{ "ok": false, "error": "..." }`
|
||||
|
||||
常见状态码:
|
||||
- `200`:成功
|
||||
- `400`:请求参数错误
|
||||
- `401`:未登录或鉴权失败
|
||||
- `403`:有登录身份但权限不足(如非管理员访问管理员接口)
|
||||
- `404`:资源不存在
|
||||
- `409`:状态冲突(例如任务已在运行)
|
||||
|
||||
## 6. 安全建议
|
||||
|
||||
1. 生产环境优先用 HTTPS。
|
||||
2. 若可控,优先使用 Bearer Token,减少明文密码在网关/代理日志出现的风险。
|
||||
3. 使用 Basic 时建议为第三方集成准备专用账号,并定期更换密码。
|
||||
4. 管理员账号只用于管理员接口,不建议用于普通业务拉取。
|
||||
|
||||
## 7. 爬虫自动化接口(管理员)
|
||||
|
||||
- 爬虫列表:`GET /admin/crawlers?status=&limit=`
|
||||
- 新增目标:`POST /admin/crawlers`,Body:`{ "url": "https://example.com" }`
|
||||
- 重新入队:`POST /admin/crawlers/{id}/queue`
|
||||
- 运行记录:`GET /admin/crawlers/{id}/runs?limit=20`
|
||||
- 守护状态:`GET /backend/crawler-guard/status`
|
||||
|
||||
说明:
|
||||
- 新地址入库后,后端守护会自动执行:规则生成(LLM)→ 自动测试 → 自动运行。
|
||||
- `crawler-guard/status` 返回 `active_requeue_interval_sec`,用于确认周期重跑间隔(默认 43200 秒,即 12 小时)。
|
||||
- 飞书群内 `@机器人` 的文本消息若含 URL,也会自动入库到爬虫列表。
|
||||
在新工单中引用
屏蔽一个用户