26dd3bb387
主要变更: 1. 动态更新功能 - 新增 Python 更新服务 (docker/update-service.py) - 添加系统更新前端页面 (frontend/src/pages/SystemUpdate.tsx) - 配置 Nginx 代理更新服务 API - 更新 Docker 启动脚本支持多进程管理 - 修复权限验证接口 (AuthController.verify) 2. Release 创建脚本 - 新增 create-release.sh 脚本支持快速创建 GitHub Release - 支持自动拼接 -beta 后缀(pre-release) - 支持无交互模式(--yes 参数) - 添加详细的使用文档 3. GitHub Actions 增强 - 添加更新包构建和上传流程 - 支持 Pre-release 检测和过滤 4. 文档完善 - 添加动态更新技术方案文档 - 添加 Docker 版本号确定流程文档 - 添加 Release 脚本使用说明
209 lines
6.1 KiB
Markdown
209 lines
6.1 KiB
Markdown
# 动态更新功能实现检查报告
|
||
|
||
基于 `docs/zh/DYNAMIC_UPDATE.md` 文档和现有代码,检查动态更新功能的实现情况。
|
||
|
||
## ✅ 已实现的功能
|
||
|
||
### 1. 后端更新服务
|
||
- ✅ `docker/update-service.py` 已实现
|
||
- 检查更新:`GET /check`
|
||
- 执行更新:`POST /update`
|
||
- 更新状态:`GET /status`
|
||
- 更新日志:`GET /logs`
|
||
- 获取版本:`GET /version`
|
||
- 健康检查:`GET /health`
|
||
- Pre-release 支持:通过 `ALLOW_PRERELEASE` 环境变量控制
|
||
|
||
### 2. Nginx 配置
|
||
- ✅ `docker/nginx.conf` 已配置
|
||
- `/api/update/` 路径代理到 `http://localhost:9090/`
|
||
- 正确传递 Authorization 头
|
||
- 超时设置合理(300秒)
|
||
|
||
### 3. Docker 启动脚本
|
||
- ✅ `docker/start.sh` 已实现
|
||
- 启动更新服务(端口 9090)
|
||
- 启动后端服务(端口 8000)
|
||
- 启动 Nginx(前台运行)
|
||
- 正确的进程清理逻辑
|
||
|
||
### 4. Dockerfile
|
||
- ✅ `Dockerfile` 已配置
|
||
- 安装 Python 和 Flask
|
||
- 复制更新服务脚本
|
||
- 创建必要的目录
|
||
- 支持混合编译方案(`BUILD_IN_DOCKER` 参数)
|
||
|
||
### 5. GitHub Actions
|
||
- ✅ `.github/workflows/docker-build.yml` 已配置
|
||
- 构建后端 JAR
|
||
- 构建前端
|
||
- 打包更新包
|
||
- 计算校验和
|
||
- 上传到 Release Assets
|
||
- Pre-release 检测和过滤
|
||
|
||
### 6. 前端更新界面
|
||
- ✅ `frontend/src/pages/SystemUpdate.tsx` 已实现
|
||
- 显示当前版本
|
||
- 检查更新
|
||
- 显示更新信息
|
||
- 执行更新
|
||
- 更新进度显示
|
||
- 错误处理
|
||
|
||
### 7. 权限验证端点
|
||
- ✅ `/api/auth/verify` 端点已存在
|
||
- 位置:`backend/src/main/kotlin/com/wrbug/polymarketbot/controller/auth/AuthController.kt`
|
||
|
||
## ⚠️ 发现的问题
|
||
|
||
### 问题 1: `/api/auth/verify` 接口逻辑错误
|
||
|
||
**位置**: `backend/src/main/kotlin/com/wrbug/polymarketbot/controller/auth/AuthController.kt:192-212`
|
||
|
||
**问题**:
|
||
```kotlin
|
||
// 检查是否为管理员
|
||
val role = httpRequest.getAttribute("role") as? String
|
||
if (role != "ADMIN") {
|
||
return ResponseEntity.status(403).body(...)
|
||
}
|
||
```
|
||
|
||
**原因**:
|
||
1. JWT 拦截器(`JwtAuthenticationInterceptor`)只设置了 `username` 到 request attributes,**没有设置 `role`**
|
||
2. User 实体**没有 `role` 字段**,而是使用 `isDefault` 字段来判断是否为管理员(默认账户就是管理员)
|
||
|
||
**修复方案**:
|
||
需要修改 `/api/auth/verify` 接口,检查用户是否为默认账户:
|
||
|
||
```kotlin
|
||
@GetMapping("/verify")
|
||
fun verify(httpRequest: HttpServletRequest): ResponseEntity<ApiResponse<Unit>> {
|
||
return try {
|
||
val username = httpRequest.getAttribute("username") as? String
|
||
if (username == null) {
|
||
return ResponseEntity.status(401).body(ApiResponse.error(ErrorCode.AUTH_ERROR, "未认证", messageSource))
|
||
}
|
||
|
||
// 检查是否为默认账户(管理员)
|
||
val user = userRepository.findByUsername(username)
|
||
if (user == null || !user.isDefault) {
|
||
return ResponseEntity.status(403).body(ApiResponse.error(ErrorCode.AUTH_ERROR, "需要管理员权限", messageSource))
|
||
}
|
||
|
||
ResponseEntity.ok(ApiResponse.success(Unit))
|
||
} catch (e: Exception) {
|
||
logger.error("验证权限异常: ${e.message}", e)
|
||
ResponseEntity.status(500).body(ApiResponse.error(ErrorCode.SERVER_ERROR, "验证失败", messageSource))
|
||
}
|
||
}
|
||
```
|
||
|
||
**需要的依赖**:
|
||
- 在 `AuthController` 中注入 `UserRepository`
|
||
|
||
### 问题 2: 前端 SystemUpdate 组件未使用 apiClient
|
||
|
||
**位置**: `frontend/src/pages/SystemUpdate.tsx`
|
||
|
||
**问题**:
|
||
组件使用了原生的 `fetch` API,而不是项目统一的 `apiClient`。虽然 `apiClient` 有拦截器自动添加 Authorization header,但原生 `fetch` 不会自动添加。
|
||
|
||
**当前代码**:
|
||
```typescript
|
||
const response = await fetch('/api/update/execute', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
})
|
||
```
|
||
|
||
**修复方案**:
|
||
有两种方案:
|
||
|
||
**方案 1(推荐)**: 使用 `apiClient`
|
||
```typescript
|
||
import { apiClient } from '../services/api'
|
||
|
||
const response = await apiClient.post('/update/execute', {})
|
||
```
|
||
|
||
**方案 2**: 手动添加 Authorization header
|
||
```typescript
|
||
const token = localStorage.getItem('token')
|
||
const response = await fetch('/api/update/execute', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': `Bearer ${token}`
|
||
}
|
||
})
|
||
```
|
||
|
||
**影响**:
|
||
- 当前如果用户已登录,token 在 localStorage 中,Nginx 会传递 Authorization 头
|
||
- 但使用 `apiClient` 更统一,且可以处理 token 刷新等情况
|
||
|
||
## 📋 已修复的问题
|
||
|
||
### 后端 ✅
|
||
1. ✅ 已修复 `AuthController.verify()` 方法
|
||
- ✅ 移除了错误的 `role` 检查
|
||
- ✅ 添加了 `UserRepository` 依赖注入
|
||
- ✅ 正确检查用户是否为默认账户(`isDefault == true`)
|
||
|
||
### 前端 ✅
|
||
2. ✅ 已修复 `SystemUpdate.tsx` 组件
|
||
- ✅ 将所有 `fetch` 调用替换为 `apiClient`
|
||
- ✅ 确保自动携带 Authorization header
|
||
- ✅ 统一错误处理逻辑
|
||
|
||
## ✅ 其他检查项
|
||
|
||
### 更新服务功能完整性
|
||
- ✅ 检查更新(无需权限)
|
||
- ✅ 获取版本(无需权限)
|
||
- ✅ 执行更新(需要管理员权限)
|
||
- ✅ 获取日志(需要管理员权限)
|
||
- ✅ 获取状态(无需权限)
|
||
|
||
### 更新流程完整性
|
||
- ✅ 下载更新包
|
||
- ✅ 备份当前版本
|
||
- ✅ 替换文件
|
||
- ✅ 重启后端
|
||
- ✅ 健康检查
|
||
- ✅ 自动回滚
|
||
|
||
### 文档完整性
|
||
- ✅ 技术方案文档存在
|
||
- ✅ 架构设计清晰
|
||
- ✅ 使用流程说明完整
|
||
|
||
## 📝 总结
|
||
|
||
**整体实现度**: 100% ✅
|
||
|
||
**已修复的问题**:
|
||
1. ✅ `/api/auth/verify` 接口已修复(现在正确检查默认账户而非 role)
|
||
2. ✅ 前端组件已改用 `apiClient` 保持一致性
|
||
|
||
**功能状态**:
|
||
- ✅ 所有核心功能已实现
|
||
- ✅ 所有问题已修复
|
||
- ✅ 代码质量良好,无 lint 错误
|
||
|
||
**下一步**:
|
||
1. 进行集成测试,验证更新流程端到端是否正常工作
|
||
2. 测试权限验证是否生效(非管理员用户应无法执行更新)
|
||
|
||
---
|
||
|
||
**检查日期**: 2026-01-20
|
||
**最后更新**: 2026-01-20(已修复所有问题)
|
||
**检查人**: AI Assistant
|
||
|