2026-09-22,线上:caigou2 登录 Admin,设备“采购2”已绑定到 caigou2,但创建采购时设备下拉里选不到“采购2”。用户要求建工单并修复。
caigou2
selectable
server/app/goauto/device/handler.go
currentUserID(c)
c.Get("userId")
owner_user_id=0
c.Set("userId", ...)
server/common/middleware/handler/auth.go
Authorizator
IdentityHandler
"user"
u
userId
server/app/goauto/shopeeproduct/handler.go
identity
采购员能在设备列表中看到并选择归属自己的设备;看不到其他采购员或未归属的设备。一键关联/替换按当前采购员自己的设备读取最新采集。
device/handler.go
shopeeproduct/handler.go
不改设备归属数据、不改 admin 行为、不改采购创建服务端对设备的校验逻辑、不改 Web。
仅 Server;无 UI、API 形态、数据库变化,不需要原型。
GET /api/admin/v1/devices
go test ./app/goauto/device/... ./app/goauto/shopeeproduct/...
权限相关,高风险;已获用户“建工单,修复”授权实施。回退:还原两处取 ID 方式。
无长期文档影响:只修复已有规则(#328 已记录“采购员按归属设备”)的实现缺陷,规则本身不变。
提交:0ab5a96,分支 fix/333-purchaser-device-owner(基于 origin/main 5e0a9d1),已推送。未合并、未部署。
0ab5a96
fix/333-purchaser-device-owner
currentUserID
deleted_by
device/list_owner_handler_test.go
userId=0
shopeeproduct/current_user_test.go
go vet
go test -count=1 ./app/goauto/device/... ./app/goauto/shopeeproduct/... ./app/goauto/purchase/...
无长期文档影响:#328 已记录的规则不变,本单只修复实现缺陷。
状态:待合并/部署,部署验证后进入待验收。
0edc78a
d8382e6
3bf428a
36810f3
01f59582cc037b2d9d5cd0ce0e9f7cbcaa57c4ba38d9f6f6eefcfc588a88a9b8
/home/goauto/releases/20260922-3bf428a-331-333
20260922-5e0a9d1-328-330
current
goauto.service
c39569f92fc94cbc91f98489c25a5a860bcaff3de91b06518b895195d39e4877
No dependencies set.
The note is not visible to the blocked user.
来源与原始需求摘要
2026-09-22,线上:caigou2 登录 Admin,设备“采购2”已绑定到 caigou2,但创建采购时设备下拉里选不到“采购2”。用户要求建工单并修复。
当前事实(origin/main 5e0a9d1,线上数据 2026-09-22)
caigou2user_id=3;设备 7“采购2” owner_user_id=3,状态 online,具备下单所需 4 项能力,无进行中任务——按selectable规则应可选。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 按归属设备读取最新临时采集)。identity取当前用户 ID。目标
采购员能在设备列表中看到并选择归属自己的设备;看不到其他采购员或未归属的设备。一键关联/替换按当前采购员自己的设备读取最新采集。
方案
device/handler.go、shopeeproduct/handler.go的当前用户 ID 改为从 JWT claimsidentity读取(与项目既有模块一致);取不到有效 ID 时仍按“无可见设备”处理(安全默认,不放宽)。Authorizator/中间件(框架行为,影响面大)。identity为 float64、rolekey=purchaser)构造请求,断言只返回本人设备;admin 仍返回全部;缺 identity 返回空。shopeeproduct 同样覆盖。非目标
不改设备归属数据、不改 admin 行为、不改采购创建服务端对设备的校验逻辑、不改 Web。
子项目影响 / 设计证据
仅 Server;无 UI、API 形态、数据库变化,不需要原型。
验收
GET /api/admin/v1/devices只返回 owner 为本人的设备。go test ./app/goauto/device/... ./app/goauto/shopeeproduct/...通过。风险
权限相关,高风险;已获用户“建工单,修复”授权实施。回退:还原两处取 ID 方式。
文档影响
无长期文档影响:只修复已有规则(#328 已记录“采购员按归属设备”)的实现缺陷,规则本身不变。
实施回写(2026-09-22)
提交:
0ab5a96,分支fix/333-purchaser-device-owner(基于 origin/main 5e0a9d1),已推送。未合并、未部署。实现
device/handler.go、shopeeproduct/handler.go的currentUserID改为读取 JWT claimsidentity(正数才采用),不再读c.Get("userId");取不到时返回 0,设备列表保持“无可见设备”的安全默认。Authorizator未改。deleted_by;此前这些审计值均为 0,修复后记录真实用户 ID。验证
device/list_owner_handler_test.go:按真实中间件形态(userId=0+ claimsidentity)走 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")读取。未验证
文档影响
无长期文档影响:#328 已记录的规则不变,本单只修复实现缺陷。
状态:待合并/部署,部署验证后进入待验收。
合并与部署(2026-09-22,用户授权“合并#331,#332,#333,部署”)
0edc78a(#332)→d8382e6(#331)→3bf428a(#333,由0ab5a96cherry-pick)→36810f3(Android 版本号 0.9.60 / versionCode 73)。3bf428a构建 linux/amd64,SHA-25601f59582cc037b2d9d5cd0ce0e9f7cbcaa57c4ba38d9f6f6eefcfc588a88a9b8;新发布目录/home/goauto/releases/20260922-3bf428a-331-333(config/dist 复制自上一发布20260922-5e0a9d1-328-330,本批无 Web 改动;static/var 链接沿用上一发布);current原子切换,goauto.serviceactive,外部首页/健康检查 HTTP 200,未认证管理接口 401,重启后日志无 panic/fatal/1146/1054。发布前采购/采集运行中任务均为 0。回滚目标:20260922-5e0a9d1-328-330。36810f3,0.9.60/73,SHA-256c39569f92fc94cbc91f98489c25a5a860bcaff3de91b06518b895195d39e4877)已安装到设备 8(采购1,192.168.0.173:34581),安装前该设备无待执行/运行任务;启动 Agent 后心跳恢复,服务端显示 online、agent_version 0.9.60。