spark-server/internal/module/moderation/logic/apply.go
2026-09-29 16:37:36 +08:00

74 lines
2.0 KiB
Go

package logic
import (
"context"
"time"
modentity "spark-server/internal/module/moderation/entity"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/reqctx"
)
// Apply records hits and runs account penalties. Call before rejecting send.
func (s *Service) Apply(ctx context.Context, userID, conversationID int64, in *modentity.ApplyInput) error {
if in == nil || len(in.Hits) == 0 {
return nil
}
if !s.Ready() {
return errs.ErrInner
}
return s.recordHits(ctx, userID, conversationID, in.Hits)
}
// Enforce runs mute/disable after hits are recorded. Returns ErrContentBlocked when send must stop.
func (s *Service) Enforce(ctx context.Context, userID int64, res *modentity.ScanResult) error {
if res == nil {
return nil
}
switch res.Action {
case modentity.ActionReject, modentity.ActionHide:
return errs.ErrContentBlocked
case modentity.ActionMute:
if s.users == nil || res.MuteSeconds <= 0 {
return errs.ErrContentBlocked
}
until := time.Now().Add(time.Duration(res.MuteSeconds) * time.Second)
if err := s.users.ExtendSendMutedUntil(ctx, userID, until); err != nil {
return err
}
return errs.ErrContentBlocked
case modentity.ActionDisable:
if s.users == nil {
return errs.ErrContentBlocked
}
if err := s.users.DisableAccount(ctx, userID); err != nil {
return err
}
return errs.ErrContentBlocked
default:
return nil
}
}
func (s *Service) recordHits(ctx context.Context, userID, conversationID int64, hits []modentity.HitMatch) error {
ip := ""
if rc := reqctx.From(ctx); rc != nil {
ip = rc.RealIP
}
now := time.Now()
rows := make([]HitRecord, 0, len(hits))
for i := range hits {
h := hits[i]
id, err := s.ids.NextID()
if err != nil {
return err
}
rows = append(rows, HitRecord{
ID: id, UserID: userID, ConversationID: conversationID,
WordID: h.WordID, Category: h.Category, Action: h.Action.Effective(),
Excerpt: h.Excerpt, RealIP: ip, CreatedAt: now,
})
}
return s.repo.InsertHits(ctx, rows)
}