1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-26 18:56:24 -07:00
gochan/pkg/gcsql/filterhandlers.go

224 lines
6.2 KiB
Go

package gcsql
import (
"errors"
"fmt"
"net/http"
"regexp"
"strings"
)
const (
StringField FieldType = iota
BooleanField
)
var (
// filterFieldHandlers = make(map[string]FilterConditionHandler)
filterFieldHandlers map[string]FilterConditionHandler
)
type FieldType int
type ConditionMatchFunc func(*http.Request, *Post, *Upload, *FilterCondition) (bool, error)
type conditionHandler struct {
fieldType FieldType
matchFunc ConditionMatchFunc
}
func (ch *conditionHandler) Type() FieldType {
return ch.fieldType
}
func (ch *conditionHandler) CheckMatch(request *http.Request, post *Post, upload *Upload, fc *FilterCondition) (bool, error) {
return ch.matchFunc(request, post, upload, fc)
}
// FilterConditionHandler handles filter conditions, providing support for checking a field
type FilterConditionHandler interface {
Type() FieldType
CheckMatch(*http.Request, *Post, *Upload, *FilterCondition) (bool, error)
}
func validateConditionHandler(field string, matchFunc ConditionMatchFunc) error {
if _, ok := filterFieldHandlers[field]; ok {
return fmt.Errorf("field %q is already registered", field)
} else if field == "" {
return errors.New("condition field must not be empty")
} else if matchFunc == nil {
return errors.New("condition match function must not be nil")
}
return nil
}
func RegisterStringConditionHandler(field string, matchFunc ConditionMatchFunc) error {
if err := validateConditionHandler(field, matchFunc); err != nil {
return err
}
filterFieldHandlers[field] = &conditionHandler{
fieldType: StringField,
matchFunc: matchFunc,
}
return nil
}
func RegisterBooleanConditionHandler(field string, matchFunc ConditionMatchFunc) error {
if err := validateConditionHandler(field, matchFunc); err != nil {
return err
}
filterFieldHandlers[field] = &conditionHandler{
fieldType: BooleanField,
matchFunc: matchFunc,
}
return nil
}
func firstPost(post *Post, global bool) (bool, error) {
var board int
var err error
if !global {
board, err = post.GetBoardID()
if err != nil {
return false, err
}
}
query := `SELECT COUNT(*) FROM DBPREFIXposts `
params := []any{post.IP}
if board > 0 {
query += ` LEFT JOIN DBPREFIXthreads ON thread_id = DBPREFIXthreads.id WHERE ip = ? AND board_id = ?`
params = append(params, board)
} else {
query += ` WHERE ip = PARAM_ATON`
}
var count int
err = QueryRowTimeoutSQL(nil, query, params, []any{&count})
return count > 0, err
}
func matchString(fc *FilterCondition, checkStr string) (bool, error) {
switch fc.MatchMode {
case SubstrMatch:
return strings.Contains(checkStr, fc.Search), nil
case SubstrMatchCaseInsensitive:
return strings.Contains(strings.ToLower(checkStr), strings.ToLower(fc.Search)), nil
case RegexMatch:
re, err := regexp.Compile(fc.Search)
if err != nil {
return false, err
}
return re.MatchString(checkStr), nil
case ExactMatch:
return checkStr == fc.Search, nil
}
return false, ErrInvalidStringMatchMode
}
func init() {
filterFieldHandlers = map[string]FilterConditionHandler{
"name": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, p.Name)
},
},
"trip": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, p.Tripcode)
},
},
"email": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, p.Email)
},
},
"subject": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, p.Subject)
},
},
"body": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, p.MessageRaw)
},
},
"firsttimeboard": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
return firstPost(p, false)
},
},
"notfirsttimeboard": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
first, err := firstPost(p, false)
return !first, err
},
},
"firsttimesite": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
return firstPost(p, true)
},
},
"notfirsttimesite": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
first, err := firstPost(p, true)
return !first, err
},
},
"isop": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
return p.IsTopPost, nil
},
},
"notop": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, _ *FilterCondition) (bool, error) {
return !p.IsTopPost, nil
},
},
"hasfile": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, u *Upload, fc *FilterCondition) (bool, error) {
return u != nil, nil
},
},
"nofile": &conditionHandler{
fieldType: BooleanField,
matchFunc: func(r *http.Request, p *Post, u *Upload, fc *FilterCondition) (bool, error) {
return u == nil, nil
},
},
"filename": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, u *Upload, fc *FilterCondition) (bool, error) {
if u == nil {
return false, nil
}
return matchString(fc, u.OriginalFilename)
},
},
"checksum": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, u *Upload, fc *FilterCondition) (bool, error) {
if u == nil {
return false, nil
}
return u.Checksum == fc.Search, nil
},
},
"useragent": &conditionHandler{
fieldType: StringField,
matchFunc: func(r *http.Request, p *Post, _ *Upload, fc *FilterCondition) (bool, error) {
return matchString(fc, r.UserAgent())
},
},
}
}