优化违禁词
This commit is contained in:
@@ -3,6 +3,7 @@ package handler
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"backend/internal/model"
|
||||
@@ -57,7 +58,23 @@ func (h *AdminReadHandler) Logs(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
items, total, stats, err := h.admin.Logs(c.Request.Context(), limit, offset, kind, status, nil, since, "", "", c.Query("source"), false, false, false)
|
||||
// ?user= — server-side 用户搜索: resolve the term to matching user ids
|
||||
// (name/email/id contains, case-insensitive) and filter rows to those users.
|
||||
// A term that matches nobody must return zero rows, not the unfiltered list.
|
||||
var userIDs []string
|
||||
if term := strings.TrimSpace(c.Query("user")); term != "" {
|
||||
ids, uerr := h.admin.MatchUserIDs(c.Request.Context(), term)
|
||||
if uerr != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load logs"})
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
ids = []string{"__no_match__"}
|
||||
}
|
||||
userIDs = ids
|
||||
}
|
||||
|
||||
items, total, stats, err := h.admin.Logs(c.Request.Context(), limit, offset, kind, status, nil, since, "", userIDs, strings.TrimSpace(c.Query("q")), "", c.Query("source"), false, false, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load logs"})
|
||||
return
|
||||
|
||||
@@ -77,6 +77,30 @@ func (h *BannedWordsHandler) Import(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"added": added, "skipped": skipped})
|
||||
}
|
||||
|
||||
// Hits — 违禁词触发列表: who triggered which word and when, newest first,
|
||||
// with server-side pagination + ?q= search (违禁词/用户名/提示词, 跨页).
|
||||
func (h *BannedWordsHandler) Hits(c *gin.Context) {
|
||||
limit := parseInt(c.Query("limit"), 50)
|
||||
offset := parseInt(c.Query("offset"), 0)
|
||||
items, total, err := h.words.ListHits(c.Request.Context(), strings.TrimSpace(c.Query("q")), limit, offset)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load banned word hits"})
|
||||
return
|
||||
}
|
||||
out := make([]gin.H, 0, len(items))
|
||||
for _, hit := range items {
|
||||
out = append(out, gin.H{
|
||||
"id": hit.ID,
|
||||
"word": hit.Word,
|
||||
"user_id": hit.UserID,
|
||||
"user_name": hit.UserName,
|
||||
"prompt": hit.Prompt,
|
||||
"created_at": hit.CreatedAt,
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"data": out, "total": total})
|
||||
}
|
||||
|
||||
func (h *BannedWordsHandler) Delete(c *gin.Context) {
|
||||
n, err := h.words.Delete(c.Request.Context(), c.Param("id"))
|
||||
if err != nil {
|
||||
|
||||
@@ -79,7 +79,7 @@ func (h *PaymentHandler) MyOrders(c *gin.Context) {
|
||||
}
|
||||
limit := parseInt(c.Query("limit"), 20)
|
||||
offset := parseInt(c.Query("offset"), 0)
|
||||
orders, total, err := h.pay.ListByUser(c.Request.Context(), user.ID, c.Query("status"), limit, offset)
|
||||
orders, total, err := h.pay.ListByUser(c.Request.Context(), user.ID, c.Query("status"), strings.TrimSpace(c.Query("q")), limit, offset)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load orders"})
|
||||
return
|
||||
@@ -129,7 +129,7 @@ func (h *PaymentHandler) AdminOrders(c *gin.Context) {
|
||||
status := c.Query("status")
|
||||
limit := parseInt(c.Query("limit"), 100)
|
||||
offset := parseInt(c.Query("offset"), 0)
|
||||
orders, total, err := h.pay.ListAll(c.Request.Context(), status, limit, offset)
|
||||
orders, total, err := h.pay.ListAll(c.Request.Context(), status, strings.TrimSpace(c.Query("q")), limit, offset)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load orders"})
|
||||
return
|
||||
|
||||
@@ -229,7 +229,21 @@ func (h *UserGenerationHandler) Logs(c *gin.Context) {
|
||||
// media=1 (画图台 grid): only pending rows or rows with a stored file, so a
|
||||
// deleted work's blanked row doesn't consume one of the grid's slots.
|
||||
mediaOnly := c.Query("media") == "1"
|
||||
items, total, stats, err := h.admin.Logs(c.Request.Context(), limit, offset, kind, status, statuses, nil, userID, excludeSource, source, hasFile, excludeShowcase, mediaOnly)
|
||||
// ?user= — admin-only 用户搜索 (the 日志管理 page with scope=all). Ignored for
|
||||
// normal users, whose rows are already pinned to their own userID.
|
||||
var userIDs []string
|
||||
if term := strings.TrimSpace(c.Query("user")); term != "" && userID == "" {
|
||||
ids, uerr := h.admin.MatchUserIDs(c.Request.Context(), term)
|
||||
if uerr != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load logs"})
|
||||
return
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
ids = []string{"__no_match__"}
|
||||
}
|
||||
userIDs = ids
|
||||
}
|
||||
items, total, stats, err := h.admin.Logs(c.Request.Context(), limit, offset, kind, status, statuses, nil, userID, userIDs, strings.TrimSpace(c.Query("q")), excludeSource, source, hasFile, excludeShowcase, mediaOnly)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": "failed to load logs"})
|
||||
return
|
||||
@@ -264,13 +278,18 @@ func (h *UserGenerationHandler) Logs(c *gin.Context) {
|
||||
} else {
|
||||
userName = item.UserID
|
||||
}
|
||||
var accountName any
|
||||
if item.AccountID != "" {
|
||||
if label, ok := accountByID[item.AccountID]; ok {
|
||||
accountName = label
|
||||
} else {
|
||||
accountName = item.AccountID
|
||||
// Provider account identity is admin-only: normal users must not see
|
||||
// which upstream account (email) fulfilled their generation.
|
||||
var accountName, accountID any
|
||||
if userID == "" {
|
||||
if item.AccountID != "" {
|
||||
if label, ok := accountByID[item.AccountID]; ok {
|
||||
accountName = label
|
||||
} else {
|
||||
accountName = item.AccountID
|
||||
}
|
||||
}
|
||||
accountID = emptyStringNil(item.AccountID)
|
||||
}
|
||||
out = append(out, gin.H{
|
||||
"id": item.ID,
|
||||
@@ -287,7 +306,7 @@ func (h *UserGenerationHandler) Logs(c *gin.Context) {
|
||||
"source": emptyStringNil(item.Source),
|
||||
"user_id": emptyStringNil(item.UserID),
|
||||
"user_name": userName,
|
||||
"account_id": emptyStringNil(item.AccountID),
|
||||
"account_id": accountID,
|
||||
"account": accountName,
|
||||
"cost": item.Cost,
|
||||
"elapsed_ms": item.ElapsedMS,
|
||||
|
||||
Reference in New Issue
Block a user