feat(ops): ECR-007 行为分析与 ECR-008 内容运营后台
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

落地埋点 ingest/数据看板、首页宫格 CMS 与测评上下架;含账号引导、问答流式与免责声明去重,以及 review P1 审计同事务修复。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-07 02:26:16 +08:00
co-authored by Cursor
parent 7e9023f0a8
commit 7ab9add5dd
132 changed files with 8276 additions and 491 deletions
@@ -0,0 +1,127 @@
package integration_test
import (
"encoding/json"
"net/http"
"testing"
)
func TestOpsContentPhaseC(t *testing.T) {
r, _ := setupAPI(t)
env, _ := doJSON(t, r, http.MethodGet, "/api/v1/home/tools", nil, "")
var home struct {
Items []map[string]any `json:"items"`
}
if err := json.Unmarshal(env.Data, &home); err != nil || len(home.Items) < 6 {
t.Fatalf("home tools seed: %v len=%d", err, len(home.Items))
}
loginEnv, code := doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/auth/login", map[string]string{
"username": "admin", "password": "change-me",
}, "")
if code != http.StatusOK {
t.Fatalf("login http=%d", code)
}
var login struct {
Token string `json:"token"`
}
_ = json.Unmarshal(loginEnv.Data, &login)
adminTools, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/home/tools", nil, login.Token)
if code != http.StatusOK || adminTools.Code != 0 {
t.Fatalf("admin tools http=%d code=%d", code, adminTools.Code)
}
var all struct {
Items []map[string]any `json:"items"`
}
_ = json.Unmarshal(adminTools.Data, &all)
if len(all.Items) == 0 {
t.Fatal("expected seeded tools")
}
// disable first tool
all.Items[0]["enabled"] = false
putEnv, code := doAdminJSON(t, r, http.MethodPut, "/api/v1/admin/home/tools", map[string]any{
"items": all.Items,
}, login.Token)
if code != http.StatusOK || putEnv.Code != 0 {
t.Fatalf("put tools http=%d code=%d msg=%s", code, putEnv.Code, putEnv.Message)
}
auditEnv, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/audit-logs?limit=5", nil, login.Token)
if code != http.StatusOK {
t.Fatalf("audit http=%d", code)
}
var audits struct {
Items []struct {
Action string `json:"action"`
} `json:"items"`
}
_ = json.Unmarshal(auditEnv.Data, &audits)
foundAudit := false
for _, a := range audits.Items {
if a.Action == "home_tools.replace" {
foundAudit = true
break
}
}
if !foundAudit {
t.Fatalf("expected home_tools.replace audit, got %+v", audits.Items)
}
env, _ = doJSON(t, r, http.MethodGet, "/api/v1/home/tools", nil, "")
_ = json.Unmarshal(env.Data, &home)
enabledN := len(home.Items)
if enabledN >= len(all.Items) {
t.Fatalf("expected fewer enabled tools after disable, pub=%d admin=%d", enabledN, len(all.Items))
}
// restore all enabled for shared DB
for i := range all.Items {
all.Items[i]["enabled"] = true
}
_, _ = doAdminJSON(t, r, http.MethodPut, "/api/v1/admin/home/tools", map[string]any{"items": all.Items}, login.Token)
scalesEnv, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/scales", nil, login.Token)
if code != http.StatusOK {
t.Fatalf("scales http=%d", code)
}
var scales struct {
Items []struct {
ID string `json:"id"`
Slug string `json:"slug"`
Status string `json:"status"`
} `json:"items"`
}
_ = json.Unmarshal(scalesEnv.Data, &scales)
if len(scales.Items) == 0 {
t.Fatal("no scales")
}
target := scales.Items[0]
patch, code := doAdminJSON(t, r, http.MethodPatch, "/api/v1/admin/scales/"+target.ID, map[string]string{
"status": "draft",
}, login.Token)
if code != http.StatusOK || patch.Code != 0 {
t.Fatalf("patch http=%d code=%d msg=%s", code, patch.Code, patch.Message)
}
// published list should not include draft slug — needs registered user
key := mustRegister(t, r)
listEnv, _ := doJSON(t, r, http.MethodGet, "/api/v1/scales", nil, key)
var pub struct {
Items []struct {
Slug string `json:"slug"`
} `json:"items"`
}
_ = json.Unmarshal(listEnv.Data, &pub)
for _, it := range pub.Items {
if it.Slug == target.Slug {
t.Fatalf("draft scale %s still in published list", target.Slug)
}
}
// restore published so other tests aren't flaky if shared DB
_, _ = doAdminJSON(t, r, http.MethodPatch, "/api/v1/admin/scales/"+target.ID, map[string]string{
"status": "published",
}, login.Token)
}