优化违禁词

This commit is contained in:
2026-07-06 12:18:09 +08:00
parent 713cca8f67
commit 89e0a9df9f
20 changed files with 412 additions and 94 deletions
+27 -1
View File
@@ -112,7 +112,7 @@ func (s *AdminReadService) ModelsView(ctx context.Context) ([]map[string]any, er
return out, nil
}
func (s *AdminReadService) Logs(ctx context.Context, limit, offset int, kind, status string, statuses []string, since *time.Time, userID, excludeSource, source string, hasFile, excludeShowcase, mediaOnly bool) ([]model.EventLog, int64, *repo.EventStats, error) {
func (s *AdminReadService) Logs(ctx context.Context, limit, offset int, kind, status string, statuses []string, since *time.Time, userID string, userIDs []string, query, excludeSource, source string, hasFile, excludeShowcase, mediaOnly bool) ([]model.EventLog, int64, *repo.EventStats, error) {
var excludeFiles []string
if excludeShowcase {
excludeFiles = s.showcaseFileList(ctx)
@@ -125,6 +125,8 @@ func (s *AdminReadService) Logs(ctx context.Context, limit, offset int, kind, st
Statuses: statuses,
Since: since,
UserID: userID,
UserIDs: userIDs,
Query: query,
ExcludeSource: excludeSource,
Source: source,
HasFile: hasFile,
@@ -147,6 +149,30 @@ func (s *AdminReadService) Logs(ctx context.Context, limit, offset int, kind, st
return items, total, stats, nil
}
// MatchUserIDs resolves an admin 用户搜索 term to the set of user ids whose
// name, email or id contains the term (case-insensitive). Returns a non-nil,
// possibly empty slice — an empty slice means "no user matched" and the caller
// should return zero rows rather than dropping the filter.
func (s *AdminReadService) MatchUserIDs(ctx context.Context, term string) ([]string, error) {
term = strings.ToLower(strings.TrimSpace(term))
if term == "" {
return nil, nil
}
users, err := s.users.List(ctx)
if err != nil {
return nil, err
}
out := []string{}
for _, u := range users {
if strings.Contains(strings.ToLower(u.Name), term) ||
strings.Contains(strings.ToLower(u.Email), term) ||
strings.Contains(strings.ToLower(u.ID), term) {
out = append(out, u.ID)
}
}
return out, nil
}
// UserNameMap builds an id -> display name lookup (name, else email, else id)
// used to annotate admin log rows with user_name (mirrors admin.py:584-596).
func (s *AdminReadService) UserNameMap(ctx context.Context) (map[string]string, error) {
+18 -4
View File
@@ -249,12 +249,26 @@ func (s *PaymentService) GetForUser(ctx context.Context, userID, orderID string)
return o, nil
}
func (s *PaymentService) ListByUser(ctx context.Context, userID, status string, limit, offset int) ([]model.Order, int64, error) {
return s.orders.ListByUser(ctx, userID, status, limit, offset)
func (s *PaymentService) ListByUser(ctx context.Context, userID, status, query string, limit, offset int) ([]model.Order, int64, error) {
return s.orders.ListByUser(ctx, userID, status, query, limit, offset)
}
func (s *PaymentService) ListAll(ctx context.Context, status string, limit, offset int) ([]model.Order, int64, error) {
return s.orders.List(ctx, status, limit, offset)
// ListAll — admin order list. A search query also matches 用户名/邮箱: resolve
// the term to user ids first so "张三" finds that user's orders.
func (s *PaymentService) ListAll(ctx context.Context, status, query string, limit, offset int) ([]model.Order, int64, error) {
var userIDs []string
if term := strings.ToLower(strings.TrimSpace(query)); term != "" {
if users, err := s.users.List(ctx); err == nil {
for _, u := range users {
if strings.Contains(strings.ToLower(u.Name), term) ||
strings.Contains(strings.ToLower(u.Email), term) ||
strings.Contains(strings.ToLower(u.ID), term) {
userIDs = append(userIDs, u.ID)
}
}
}
}
return s.orders.List(ctx, status, query, userIDs, limit, offset)
}
// UserNames maps user id → display name (name, else email, else id) so the admin
+6 -2
View File
@@ -268,11 +268,15 @@ func (s *V1Service) checkBannedPrompt(ctx context.Context, principal *APIPrincip
if term == "" || !strings.Contains(lower, term) {
continue
}
userID := ""
userID, userName := "", ""
if principal != nil && principal.User != nil {
userID = principal.User.ID
userName = principal.User.Name
if userName == "" {
userName = principal.User.Email
}
}
s.banned.RecordHit(ctx, w.ID, userID)
s.banned.RecordHit(ctx, w.ID, w.Word, userID, userName, prompt)
return fmt.Errorf("%w: banned word \"%s\"", ErrBannedPrompt, w.Word)
}
return nil