feat(ECR-010): Ops-E 系统运营;修复登出解绑;P2 Complete
ci / h5 (push) Canceled after 0s
ci / api (push) Canceled after 0s
ci / ess-docs (push) Canceled after 0s

落地管理员 RBAC/封禁/推送任务 stub,logout 解绑 device 并统一各页 ensureAccount,同时收口 P2 生日生成与状态文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jackyu66git
2026-08-11 18:54:59 +08:00
co-authored by Cursor
parent 0ee4d4f5ae
commit 5ceb3ce749
85 changed files with 2098 additions and 103 deletions
+31
View File
@@ -38,6 +38,15 @@ func DeviceAuth(pool *pgxpool.Pool) gin.HandlerFunc {
WHERE token=$1 AND revoked_at IS NULL AND expires_at > now()`, tok,
).Scan(&uid)
if err == nil {
if banned, berr := userIsBanned(c.Request.Context(), pool, uid); berr != nil {
response.Fail(c, http.StatusInternalServerError, 50001, "identity unavailable")
c.Abort()
return
} else if banned {
response.Fail(c, http.StatusForbidden, 40310, "账号已封禁")
c.Abort()
return
}
_, _ = pool.Exec(c.Request.Context(), `
INSERT INTO device_identities(device_key, user_id)
VALUES ($1,$2)
@@ -56,6 +65,15 @@ func DeviceAuth(pool *pgxpool.Pool) gin.HandlerFunc {
c.Abort()
return
}
if banned, berr := userIsBanned(c.Request.Context(), pool, userID); berr != nil {
response.Fail(c, http.StatusInternalServerError, 50001, "identity unavailable")
c.Abort()
return
} else if banned {
response.Fail(c, http.StatusForbidden, 40310, "账号已封禁")
c.Abort()
return
}
c.Set(string(UserIDKey), userID.String())
c.Header(DeviceKeyHeader, key)
c.Next()
@@ -149,3 +167,16 @@ func newDeviceKey() string {
_, _ = rand.Read(b)
return "dev_" + hex.EncodeToString(b)
}
func userIsBanned(ctx context.Context, pool *pgxpool.Pool, userID uuid.UUID) (bool, error) {
var status string
err := pool.QueryRow(ctx, `
SELECT status FROM users WHERE id=$1 AND deleted_at IS NULL`, userID).Scan(&status)
if errors.Is(err, pgx.ErrNoRows) {
return false, nil
}
if err != nil {
return false, err
}
return status == "banned", nil
}