AI 托管账号支持筛选未托管
筛选只有「仅已托管」一个选项,想找还没开启的账号只能翻页。补上 managed=0:未托管既包括从未绑定的账号,也包括绑定后被关闭的账号, 运营要开启的正是这两类,所以放在一起。 测试覆盖三种状态,并断言两个筛选相加等于全部、没有重复计数。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
151834caac
commit
b42743c882
@@ -33,8 +33,14 @@ func (a *App) adminAIAgents(w http.ResponseWriter, r *http.Request) {
|
||||
fail(w, http.StatusBadRequest, 20001, err.Error())
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(r.URL.Query().Get("managed")) == "1" {
|
||||
// "0" is not the absence of a filter here: an account is unmanaged both when
|
||||
// it has no binding at all and when its binding is switched off, and the
|
||||
// operator looking for accounts to turn on wants to see both.
|
||||
switch strings.TrimSpace(r.URL.Query().Get("managed")) {
|
||||
case "1":
|
||||
where += " AND g.user_id IS NOT NULL AND g.enabled=1"
|
||||
case "0":
|
||||
where += " AND (g.user_id IS NULL OR g.enabled=0)"
|
||||
}
|
||||
// Same keyword shape as the user list: nickname or 星遇号.
|
||||
if keyword := strings.TrimSpace(r.URL.Query().Get("keyword")); keyword != "" {
|
||||
|
||||
@@ -246,3 +246,63 @@ func TestAIReplyRetriesAfterReasoningExhaustsBudgetMySQL(t *testing.T) {
|
||||
t.Fatalf("calls = %d, want 2", calls)
|
||||
}
|
||||
}
|
||||
|
||||
// The managed filter has three states, and "0" is a real one: an account is
|
||||
// unmanaged both when it was never bound and when its binding is switched off.
|
||||
func TestAdminAIAgentsManagedFilterMySQL(t *testing.T) {
|
||||
db := isolatedIMDatabase(t)
|
||||
a := &App{db: db, hub: NewHub(), config: Config{Environment: "development", JWTSecret: "isolated-im-regression-secret-only"}}
|
||||
for _, statement := range []string{
|
||||
`UPDATE users SET is_test=1,test_batch='regression' WHERE id IN (1,2,3)`,
|
||||
`INSERT INTO ai_agents(user_id,model_id,enabled) VALUES(1,0,1),(2,0,0)`,
|
||||
} {
|
||||
if _, err := db.Exec(statement); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
list := func(query string) []int64 {
|
||||
t.Helper()
|
||||
var payload struct {
|
||||
Items []struct {
|
||||
UserID int64 `json:"userId"`
|
||||
} `json:"items"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
if err := json.Unmarshal(imTestCall(t, a.adminAIAgents, 1, "GET", "/admin/v1/ai/agents"+query, "", 200), &payload); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ids := []int64{}
|
||||
for _, item := range payload.Items {
|
||||
ids = append(ids, item.UserID)
|
||||
}
|
||||
if payload.Total != len(ids) {
|
||||
t.Fatalf("total=%d 与条目数 %d 不一致", payload.Total, len(ids))
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
if got := list("?managed=1"); len(got) != 1 || got[0] != 1 {
|
||||
t.Fatalf("仅已托管 = %v, want [1]", got)
|
||||
}
|
||||
// Account 2 is bound but switched off, account 3 was never bound.
|
||||
got := list("?managed=0")
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("仅未托管 = %v, want 两个账号", got)
|
||||
}
|
||||
for _, want := range []int64{2, 3} {
|
||||
found := false
|
||||
for _, id := range got {
|
||||
found = found || id == want
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("仅未托管 = %v, 缺少 %d", got, want)
|
||||
}
|
||||
}
|
||||
if all := list(""); len(all) != 3 {
|
||||
t.Fatalf("全部账号 = %v, want 3 个", all)
|
||||
}
|
||||
// The two halves together are the whole list, with nothing counted twice.
|
||||
if len(list("?managed=1"))+len(list("?managed=0")) != len(list("")) {
|
||||
t.Fatal("两个筛选相加必须等于全部")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user