package logic import ( "context" modentity "spark-server/internal/module/moderation/entity" ) // Scan implements message TextFilter. No hit returns (nil, nil). func (s *Service) Scan(ctx context.Context, text string) (*modentity.ScanResult, error) { if !s.Ready() { return nil, nil } _ = ctx details, masked, ok := s.repo.MatcherFind(text) if len(details) == 0 { return nil, nil } if !ok { return &modentity.ScanResult{Action: modentity.ActionReject, Hits: toHits(details)}, nil } var actions []modentity.Action var muteSec int hits := make([]modentity.HitMatch, 0, len(details)) for i := range details { d := details[i] act := d.Action.Effective() actions = append(actions, act) if act == modentity.ActionMute { if w := s.repo.LookupWord(d.WordID); w != nil && w.MuteSeconds > muteSec { muteSec = w.MuteSeconds } } hits = append(hits, modentity.HitMatch{ WordID: d.WordID, Category: d.Category, Action: d.Action, Excerpt: d.Excerpt, ByteFrom: d.From, ByteTo: d.To, }) } best := modentity.MaxAction(actions...) res := &modentity.ScanResult{Action: best, Hits: hits, MuteSeconds: muteSec} if best == modentity.ActionReplace { res.ReplacedBody = masked } return res, nil } func toHits(details []MatchDetail) []modentity.HitMatch { out := make([]modentity.HitMatch, 0, len(details)) for i := range details { d := details[i] out = append(out, modentity.HitMatch{ WordID: d.WordID, Category: d.Category, Action: d.Action, Excerpt: d.Excerpt, ByteFrom: d.From, ByteTo: d.To, }) } return out }