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

80 lines
2.3 KiB
Go

// Package logic is sensitive-word scan, penalties, and admin word CRUD.
package logic
import (
"context"
"errors"
"time"
modentity "spark-server/internal/module/moderation/entity"
)
var ErrNotReady = errors.New("moderation: not ready")
type Repository interface {
Ready() bool
ReloadMatcher(ctx context.Context) error
ListWords(ctx context.Context, q string, category int, enabled *bool, page, size int) ([]modentity.Word, int64, error)
CreateWord(ctx context.Context, w *modentity.Word) error
UpdateWord(ctx context.Context, id int64, patch WordPatch) error
SoftDeleteWord(ctx context.Context, id int64) error
InsertHits(ctx context.Context, hits []HitRecord) error
ListHits(ctx context.Context, userID int64, category int, since, until *time.Time, page, size int) ([]HitRecord, int64, error)
LookupWord(id int64) *modentity.Word
MatcherFind(text string) ([]MatchDetail, string, bool)
}
type WordPatch func(w *modentity.Word) error
type HitRecord struct {
ID int64 `json:"id"`
UserID int64 `json:"user_id"`
ConversationID int64 `json:"conversation_id"`
WordID int64 `json:"word_id"`
Category modentity.Category `json:"category"`
Action modentity.Action `json:"action"`
Excerpt string `json:"excerpt"`
RealIP string `json:"real_ip"`
CreatedAt time.Time `json:"created_at"`
}
type MatchDetail struct {
WordID int64
Category modentity.Category
Action modentity.Action
Excerpt string
From int
To int
}
type UserModeration interface {
AssertCanSend(ctx context.Context, userID int64) error
DisableAccount(ctx context.Context, userID int64) error
ExtendSendMutedUntil(ctx context.Context, userID int64, until time.Time) error
}
type IDGen interface {
NextID() (int64, error)
}
type Service struct {
repo Repository
users UserModeration
ids IDGen
}
func NewService(repo Repository, users UserModeration, ids IDGen) *Service {
return &Service{repo: repo, users: users, ids: ids}
}
func (s *Service) Ready() bool {
return s != nil && s.repo != nil && s.repo.Ready()
}
func (s *Service) Reload(ctx context.Context) error {
if !s.Ready() {
return ErrNotReady
}
return s.repo.ReloadMatcher(ctx)
}