120 lines
3.2 KiB
Go
120 lines
3.2 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
modentity "spark-server/internal/module/moderation/entity"
|
|
modlogic "spark-server/internal/module/moderation/logic"
|
|
"spark-server/internal/pkg/sensitive"
|
|
)
|
|
|
|
// LogicBridge adapts Repo to moderation/logic.Repository.
|
|
type LogicBridge struct {
|
|
*Repo
|
|
}
|
|
|
|
func NewLogicBridge(r *Repo) *LogicBridge {
|
|
if r == nil {
|
|
return nil
|
|
}
|
|
return &LogicBridge{Repo: r}
|
|
}
|
|
|
|
func (b *LogicBridge) LookupWord(id int64) *modentity.Word {
|
|
if b == nil || b.matcher == nil {
|
|
return nil
|
|
}
|
|
row := b.matcher.WordByID(id)
|
|
if row == nil {
|
|
return nil
|
|
}
|
|
return row.entity()
|
|
}
|
|
|
|
func (b *LogicBridge) MatcherFind(text string) ([]modlogic.MatchDetail, string, bool) {
|
|
m := b.matcher.Get()
|
|
idx := sensitive.FoldAndIndex(text)
|
|
if m == nil || len(idx.Norm) == 0 {
|
|
return nil, text, true
|
|
}
|
|
rawMatches := m.FindAll(idx.Norm)
|
|
if len(rawMatches) == 0 {
|
|
return nil, text, true
|
|
}
|
|
intervals, ok := sensitive.IntervalsFromMatches(&idx, rawMatches)
|
|
masked := text
|
|
if ok {
|
|
masked = sensitive.Mask(idx.OrigBytes, intervals, "***")
|
|
}
|
|
details := make([]modlogic.MatchDetail, 0, len(rawMatches))
|
|
for _, rm := range rawMatches {
|
|
row := b.matcher.WordByID(rm.EntryID)
|
|
if row == nil {
|
|
continue
|
|
}
|
|
ent := row.entity()
|
|
from, to := 0, 0
|
|
if ok && rm.Start >= 0 && rm.End <= len(idx.OrigFrom) {
|
|
from = idx.OrigFrom[rm.Start]
|
|
to = idx.OrigTo[rm.End-1]
|
|
}
|
|
ex := sensitive.Excerpt(idx.OrigBytes, from, to, 128)
|
|
details = append(details, modlogic.MatchDetail{
|
|
WordID: ent.ID, Category: ent.Category, Action: ent.Action,
|
|
Excerpt: ex, From: from, To: to,
|
|
})
|
|
}
|
|
if len(details) == 0 {
|
|
return nil, text, true
|
|
}
|
|
return details, masked, ok
|
|
}
|
|
|
|
func (b *LogicBridge) UpdateWord(ctx context.Context, id int64, patch modlogic.WordPatch) error {
|
|
return b.Repo.UpdateWord(ctx, id, func(row *WordRow) error {
|
|
if patch == nil {
|
|
return nil
|
|
}
|
|
ent := row.entity()
|
|
if err := patch(ent); err != nil {
|
|
return err
|
|
}
|
|
row.WordRaw = ent.WordRaw
|
|
row.Word = ent.Word
|
|
row.Category = int8(ent.Category)
|
|
row.Action = int8(ent.Action)
|
|
row.MuteSeconds = ent.MuteSeconds
|
|
row.Enabled = boolToTiny(ent.Enabled)
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func (b *LogicBridge) InsertHits(ctx context.Context, hits []modlogic.HitRecord) error {
|
|
rows := make([]HitRow, 0, len(hits))
|
|
for i := range hits {
|
|
h := hits[i]
|
|
rows = append(rows, hitFromEntity(h.ID, h.UserID, h.ConversationID, modentity.HitMatch{
|
|
WordID: h.WordID, Category: h.Category, Action: h.Action, Excerpt: h.Excerpt,
|
|
}, h.RealIP, h.CreatedAt))
|
|
}
|
|
return b.Repo.InsertHits(ctx, rows)
|
|
}
|
|
|
|
func (b *LogicBridge) ListHits(ctx context.Context, userID int64, category int, since, until *time.Time, page, size int) ([]modlogic.HitRecord, int64, error) {
|
|
rows, total, err := b.Repo.ListHits(ctx, userID, category, since, until, page, size)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
out := make([]modlogic.HitRecord, 0, len(rows))
|
|
for i := range rows {
|
|
r := rows[i]
|
|
out = append(out, modlogic.HitRecord{
|
|
ID: r.ID, UserID: r.UserID, ConversationID: r.ConversationID,
|
|
WordID: r.WordID, Category: modentity.Category(r.Category), Action: modentity.Action(r.Action),
|
|
Excerpt: r.Excerpt, RealIP: r.RealIP, CreatedAt: r.CreatedAt,
|
|
})
|
|
}
|
|
return out, total, nil
|
|
}
|