采购员设备列表为空:#328 按 userId 取当前用户恒为 0 #333

Open
opened 2026-09-22 10:43:28 +08:00 by ila · 2 comments
Owner

来源与原始需求摘要

2026-09-22,线上:caigou2 登录 Admin,设备“采购2”已绑定到 caigou2,但创建采购时设备下拉里选不到“采购2”。用户要求建工单并修复。

当前事实(origin/main 5e0a9d1,线上数据 2026-09-22)

  • 线上 caigou2 user_id=3;设备 7“采购2” owner_user_id=3,状态 online,具备下单所需 4 项能力,无进行中任务——按 selectable 规则应可选。
  • #328(0661b22)在 server/app/goauto/device/handler.go 的 List 中:非 admin 时用 currentUserID(c) → c.Get("userId") 作为 owner 过滤;取不到时过滤 owner_user_id=0。
  • c.Set("userId", ...) 由 server/common/middleware/handler/auth.go 的 Authorizator 设置。go-admin jwtauth 中间件每次请求以 IdentityHandler 返回值调用 Authorizator,该 map 不含 "user" 键,故 u 为零值、userId 被设为 0。
  • 结果:所有采购员请求设备列表都被过滤为 owner_user_id=0 → 空列表。管理员不受影响,#328 测试未覆盖真实中间件路径。
  • 同一写法还在 server/app/goauto/shopeeproduct/handler.go(#328 按归属设备读取最新临时采集)。
  • 项目其他模块(product、purchase、aimatching、sybimport)使用 JWT claims identity 取当前用户 ID。

目标

采购员能在设备列表中看到并选择归属自己的设备;看不到其他采购员或未归属的设备。一键关联/替换按当前采购员自己的设备读取最新采集。

方案

  • device/handler.go、shopeeproduct/handler.go 的当前用户 ID 改为从 JWT claims identity 读取(与项目既有模块一致);取不到有效 ID 时仍按“无可见设备”处理(安全默认,不放宽)。
  • 不改 Authorizator/中间件(框架行为,影响面大)。
  • 测试:以真实 claims 形态(identity 为 float64、rolekey=purchaser)构造请求,断言只返回本人设备;admin 仍返回全部;缺 identity 返回空。shopeeproduct 同样覆盖。

非目标

不改设备归属数据、不改 admin 行为、不改采购创建服务端对设备的校验逻辑、不改 Web。

子项目影响 / 设计证据

仅 Server;无 UI、API 形态、数据库变化,不需要原型。

验收

  1. 采购员 token 调用 GET /api/admin/v1/devices 只返回 owner 为本人的设备。
  2. admin 返回全部设备。
  3. 无有效 identity 时返回空列表。
  4. shopeeproduct 最新采集按本人设备过滤。
  5. go test ./app/goauto/device/... ./app/goauto/shopeeproduct/... 通过。
  6. 部署后线上 caigou2 能选到“采购2”(部署需授权,未部署前记为未验证)。

风险

权限相关,高风险;已获用户“建工单,修复”授权实施。回退:还原两处取 ID 方式。

文档影响

无长期文档影响:只修复已有规则(#328 已记录“采购员按归属设备”)的实现缺陷,规则本身不变。

## 来源与原始需求摘要 2026-09-22,线上:caigou2 登录 Admin,设备“采购2”已绑定到 caigou2,但创建采购时设备下拉里选不到“采购2”。用户要求建工单并修复。 ## 当前事实(origin/main 5e0a9d1,线上数据 2026-09-22) - 线上 `caigou2` user_id=3;设备 7“采购2” owner_user_id=3,状态 online,具备下单所需 4 项能力,无进行中任务——按 `selectable` 规则应可选。 - #328(0661b22)在 `server/app/goauto/device/handler.go` 的 List 中:非 admin 时用 `currentUserID(c)` → `c.Get("userId")` 作为 owner 过滤;取不到时过滤 `owner_user_id=0`。 - `c.Set("userId", ...)` 由 `server/common/middleware/handler/auth.go` 的 `Authorizator` 设置。go-admin jwtauth 中间件每次请求以 `IdentityHandler` 返回值调用 `Authorizator`,该 map **不含 `"user"` 键**,故 `u` 为零值、`userId` 被设为 0。 - 结果:所有采购员请求设备列表都被过滤为 `owner_user_id=0` → 空列表。管理员不受影响,#328 测试未覆盖真实中间件路径。 - 同一写法还在 `server/app/goauto/shopeeproduct/handler.go`(#328 按归属设备读取最新临时采集)。 - 项目其他模块(product、purchase、aimatching、sybimport)使用 JWT claims `identity` 取当前用户 ID。 ## 目标 采购员能在设备列表中看到并选择归属自己的设备;看不到其他采购员或未归属的设备。一键关联/替换按当前采购员自己的设备读取最新采集。 ## 方案 - `device/handler.go`、`shopeeproduct/handler.go` 的当前用户 ID 改为从 JWT claims `identity` 读取(与项目既有模块一致);取不到有效 ID 时仍按“无可见设备”处理(安全默认,不放宽)。 - 不改 `Authorizator`/中间件(框架行为,影响面大)。 - 测试:以真实 claims 形态(`identity` 为 float64、rolekey=purchaser)构造请求,断言只返回本人设备;admin 仍返回全部;缺 identity 返回空。shopeeproduct 同样覆盖。 ## 非目标 不改设备归属数据、不改 admin 行为、不改采购创建服务端对设备的校验逻辑、不改 Web。 ## 子项目影响 / 设计证据 仅 Server;无 UI、API 形态、数据库变化,不需要原型。 ## 验收 1. 采购员 token 调用 `GET /api/admin/v1/devices` 只返回 owner 为本人的设备。 2. admin 返回全部设备。 3. 无有效 identity 时返回空列表。 4. shopeeproduct 最新采集按本人设备过滤。 5. `go test ./app/goauto/device/... ./app/goauto/shopeeproduct/...` 通过。 6. 部署后线上 caigou2 能选到“采购2”(部署需授权,未部署前记为未验证)。 ## 风险 权限相关,高风险;已获用户“建工单,修复”授权实施。回退:还原两处取 ID 方式。 ## 文档影响 无长期文档影响:只修复已有规则(#328 已记录“采购员按归属设备”)的实现缺陷,规则本身不变。
Author
Owner

实施回写(2026-09-22)

提交:0ab5a96,分支 fix/333-purchaser-device-owner(基于 origin/main 5e0a9d1),已推送。未合并、未部署。

实现

  • device/handler.go、shopeeproduct/handler.go 的 currentUserID 改为读取 JWT claims identity(正数才采用),不再读 c.Get("userId");取不到时返回 0,设备列表保持“无可见设备”的安全默认。
  • 中间件/Authorizator 未改。
  • 附带影响(同一函数,同一根因):shopeeproduct 中该函数还用于一键关联/替换的操作者、自动匹配运行的发起人、批量软删除的 deleted_by;此前这些审计值均为 0,修复后记录真实用户 ID。

验证

  • 新增 device/list_owner_handler_test.go:按真实中间件形态(userId=0 + claims identity)走 HTTP handler:采购员 3 只看到自己的设备;admin 看到全部;无 identity 的采购员看到空列表。该测试在修复前代码上失败、修复后通过(已实测)。
  • 新增 shopeeproduct/current_user_test.go:claims identity=3 → 3;缺失或负数 → 0。
  • go vet 通过;go test -count=1 ./app/goauto/device/... ./app/goauto/shopeeproduct/... ./app/goauto/purchase/... 全部通过。
  • 服务端其余位置已检索,没有其他 c.Get("userId") 读取。

未验证

  • 未部署;线上 caigou2 能否选到“采购2”待部署后验证(部署需授权)。
  • 未用 caigou1 实际登录复现(根据代码推断同样受影响)。

文档影响

无长期文档影响:#328 已记录的规则不变,本单只修复实现缺陷。

状态:待合并/部署,部署验证后进入待验收。

## 实施回写(2026-09-22) **提交**:`0ab5a96`,分支 `fix/333-purchaser-device-owner`(基于 origin/main 5e0a9d1),已推送。**未合并、未部署。** ### 实现 - `device/handler.go`、`shopeeproduct/handler.go` 的 `currentUserID` 改为读取 JWT claims `identity`(正数才采用),不再读 `c.Get("userId")`;取不到时返回 0,设备列表保持“无可见设备”的安全默认。 - 中间件/`Authorizator` 未改。 - 附带影响(同一函数,同一根因):shopeeproduct 中该函数还用于一键关联/替换的操作者、自动匹配运行的发起人、批量软删除的 `deleted_by`;此前这些审计值均为 0,修复后记录真实用户 ID。 ### 验证 - 新增 `device/list_owner_handler_test.go`:按真实中间件形态(`userId=0` + claims `identity`)走 HTTP handler:采购员 3 只看到自己的设备;admin 看到全部;无 identity 的采购员看到空列表。**该测试在修复前代码上失败、修复后通过**(已实测)。 - 新增 `shopeeproduct/current_user_test.go`:claims identity=3 → 3;缺失或负数 → 0。 - `go vet` 通过;`go test -count=1 ./app/goauto/device/... ./app/goauto/shopeeproduct/... ./app/goauto/purchase/...` 全部通过。 - 服务端其余位置已检索,没有其他 `c.Get("userId")` 读取。 ### 未验证 - 未部署;线上 caigou2 能否选到“采购2”待部署后验证(部署需授权)。 - 未用 caigou1 实际登录复现(根据代码推断同样受影响)。 ### 文档影响 无长期文档影响:#328 已记录的规则不变,本单只修复实现缺陷。 状态:待合并/部署,部署验证后进入待验收。
Author
Owner

合并与部署(2026-09-22,用户授权“合并#331,#332,#333,部署”)

  • main:0edc78a(#332)→ d8382e6(#331)→ 3bf428a(#333,由 0ab5a96 cherry-pick)→ 36810f3(Android 版本号 0.9.60 / versionCode 73)。
  • Server:从 3bf428a 构建 linux/amd64,SHA-256 01f59582cc037b2d9d5cd0ce0e9f7cbcaa57c4ba38d9f6f6eefcfc588a88a9b8;新发布目录 /home/goauto/releases/20260922-3bf428a-331-333(config/dist 复制自上一发布 20260922-5e0a9d1-328-330,本批无 Web 改动;static/var 链接沿用上一发布);current 原子切换,goauto.service active,外部首页/健康检查 HTTP 200,未认证管理接口 401,重启后日志无 panic/fatal/1146/1054。发布前采购/采集运行中任务均为 0。回滚目标:20260922-5e0a9d1-328-330。
  • Android:debug APK(commit 36810f3,0.9.60/73,SHA-256 c39569f92fc94cbc91f98489c25a5a860bcaff3de91b06518b895195d39e4877)已安装到设备 8(采购1,192.168.0.173:34581),安装前该设备无待执行/运行任务;启动 Agent 后心跳恢复,服务端显示 online、agent_version 0.9.60。
  • 未做:设备 7(采购2)当时 offline,未安装;APK 未上传到 Admin Agent 版本;Wiki 尚未更新;#333 线上采购员选设备效果、#331/#332 真机采购效果均未验证。
## 合并与部署(2026-09-22,用户授权“合并#331,#332,#333,部署”) - **main**:`0edc78a`(#332)→ `d8382e6`(#331)→ `3bf428a`(#333,由 `0ab5a96` cherry-pick)→ `36810f3`(Android 版本号 0.9.60 / versionCode 73)。 - **Server**:从 `3bf428a` 构建 linux/amd64,SHA-256 `01f59582cc037b2d9d5cd0ce0e9f7cbcaa57c4ba38d9f6f6eefcfc588a88a9b8`;新发布目录 `/home/goauto/releases/20260922-3bf428a-331-333`(config/dist 复制自上一发布 `20260922-5e0a9d1-328-330`,本批无 Web 改动;static/var 链接沿用上一发布);`current` 原子切换,`goauto.service` active,外部首页/健康检查 HTTP 200,未认证管理接口 401,重启后日志无 panic/fatal/1146/1054。发布前采购/采集运行中任务均为 0。回滚目标:`20260922-5e0a9d1-328-330`。 - **Android**:debug APK(commit `36810f3`,0.9.60/73,SHA-256 `c39569f92fc94cbc91f98489c25a5a860bcaff3de91b06518b895195d39e4877`)已安装到设备 8(采购1,192.168.0.173:34581),安装前该设备无待执行/运行任务;启动 Agent 后心跳恢复,服务端显示 online、agent_version 0.9.60。 - **未做**:设备 7(采购2)当时 offline,未安装;APK 未上传到 Admin Agent 版本;Wiki 尚未更新;#333 线上采购员选设备效果、#331/#332 真机采购效果均**未验证**。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#333