mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-09-05 11:06:23 -07:00
Add "handle if any" functionality to matching filters
This commit is contained in:
parent
26dcb34edf
commit
b1df0bf80a
8 changed files with 120 additions and 12 deletions
|
@ -498,19 +498,28 @@ func (f *Filter) handleMatch(post *Post, upload *Upload, request *http.Request)
|
|||
func (f *Filter) checkIfMatch(post *Post, upload *Upload, request *http.Request, errEv *zerolog.Event) (bool, error) {
|
||||
conditions, err := f.Conditions()
|
||||
if err != nil {
|
||||
errEv.Err(err).Caller().
|
||||
Int("filterID", f.ID).
|
||||
Msg("unable to get filter conditions")
|
||||
return false, err
|
||||
}
|
||||
|
||||
match := true
|
||||
var match bool
|
||||
for _, condition := range conditions {
|
||||
if !match {
|
||||
break
|
||||
}
|
||||
if match, err = condition.testCondition(post, upload, request, errEv); err != nil {
|
||||
// testCondition handles logging errors
|
||||
return false, err
|
||||
}
|
||||
if f.HandleIfAny && match {
|
||||
// found a matching condition, filter is set to consider any matching condition a match
|
||||
return true, nil
|
||||
}
|
||||
if !f.HandleIfAny && !match {
|
||||
// found a non-matching condition, filter is set to consider any non-matching condition a non-match
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return match, nil
|
||||
return !f.HandleIfAny, nil
|
||||
}
|
||||
|
||||
func (fc FilterCondition) testCondition(post *Post, upload *Upload, request *http.Request, errEv *zerolog.Event) (bool, error) {
|
||||
|
|
87
pkg/gcsql/filters_test.go
Normal file
87
pkg/gcsql/filters_test.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
package gcsql
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
testingPost = &Post{
|
||||
MessageRaw: "this search should match",
|
||||
}
|
||||
|
||||
checkIfMatchTestCases = []filterTestCases{
|
||||
{
|
||||
name: "basic message AND check",
|
||||
filter: &Filter{
|
||||
StaffNote: "basic message AND check",
|
||||
MatchAction: "log",
|
||||
conditions: []FilterCondition{
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "search"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "match"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "should"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "this"},
|
||||
},
|
||||
},
|
||||
args: checkIfMatchArgs{
|
||||
request: &http.Request{},
|
||||
},
|
||||
wantMatch: true,
|
||||
},
|
||||
{
|
||||
name: "basic message OR check",
|
||||
filter: &Filter{
|
||||
StaffNote: "basic message OR check",
|
||||
MatchAction: "log",
|
||||
HandleIfAny: true,
|
||||
conditions: []FilterCondition{
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "aaa"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "bbb"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "search"},
|
||||
{FilterID: 1, Field: "body", MatchMode: SubstrMatch, Search: "ssss"},
|
||||
},
|
||||
},
|
||||
args: checkIfMatchArgs{
|
||||
request: &http.Request{},
|
||||
},
|
||||
wantMatch: true,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type checkIfMatchArgs struct {
|
||||
post *Post
|
||||
upload *Upload
|
||||
request *http.Request
|
||||
}
|
||||
|
||||
type filterTestCases struct {
|
||||
name string
|
||||
filter *Filter
|
||||
args checkIfMatchArgs
|
||||
wantMatch bool
|
||||
wantErr bool
|
||||
}
|
||||
|
||||
func TestFilterCheckIfMatch(t *testing.T) {
|
||||
testLog := zerolog.New(zerolog.NewTestWriter(t))
|
||||
for _, tc := range checkIfMatchTestCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
errEv := testLog.WithLevel(zerolog.ErrorLevel)
|
||||
defer errEv.Discard()
|
||||
tc.args.post = testingPost
|
||||
gotMatch, err := tc.filter.checkIfMatch(tc.args.post, tc.args.upload, tc.args.request, errEv)
|
||||
if tc.wantErr {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
if !assert.NoError(t, err) {
|
||||
errEv.Send()
|
||||
}
|
||||
}
|
||||
assert.Equal(t, tc.wantMatch, gotMatch)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -57,12 +57,13 @@ type Board struct {
|
|||
// and will allow moderators to block posts based on the user's name, email, subject, message content, and other fields.
|
||||
// table: DBPREFIXfilters
|
||||
type Filter struct {
|
||||
ID int `json:"id"` // sql: id
|
||||
StaffID *int `json:"staff_id"` // sql: staff_id
|
||||
StaffNote string `json:"staff_note"` // sql: staff_note
|
||||
IssuedAt time.Time `json:"issued_at"` // sql: issued_at
|
||||
ID int // sql: id
|
||||
StaffID *int // sql: staff_id
|
||||
StaffNote string // sql: staff_note
|
||||
IssuedAt time.Time // sql: issued_at
|
||||
MatchAction string // sql: match_action
|
||||
MatchDetail string // sql: match_detail
|
||||
HandleIfAny bool // sql: handle_if_any
|
||||
IsActive bool // sql: is_active
|
||||
conditions []FilterCondition
|
||||
}
|
||||
|
|
|
@ -251,6 +251,7 @@ CREATE TABLE DBPREFIXfilters(
|
|||
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
match_action VARCHAR(45) NOT NULL DEFAULT 'replace',
|
||||
match_detail TEXT NOT NULL,
|
||||
handle_if_any BOOL NOT NULL DEFAULT FALSE,
|
||||
is_active BOOL NOT NULL,
|
||||
CONSTRAINT filters_staff_id_fk
|
||||
FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
|
||||
|
|
|
@ -251,6 +251,7 @@ CREATE TABLE DBPREFIXfilters(
|
|||
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
match_action VARCHAR(45) NOT NULL DEFAULT 'replace',
|
||||
match_detail TEXT NOT NULL,
|
||||
handle_if_any BOOL NOT NULL DEFAULT FALSE,
|
||||
is_active BOOL NOT NULL,
|
||||
CONSTRAINT filters_staff_id_fk
|
||||
FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
|
||||
|
@ -278,7 +279,7 @@ CREATE TABLE DBPREFIXfilter_conditions(
|
|||
CONSTRAINT filter_conditions_filter_id_fk
|
||||
FOREIGN KEY(filter_id) REFERENCES DBPREFIXfilters(id)
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '')
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '' OR match_mode = 3)
|
||||
);
|
||||
|
||||
CREATE TABLE DBPREFIXfilter_hits(
|
||||
|
|
|
@ -251,6 +251,7 @@ CREATE TABLE DBPREFIXfilters(
|
|||
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
match_action VARCHAR(45) NOT NULL DEFAULT 'replace',
|
||||
match_detail TEXT NOT NULL,
|
||||
handle_if_any BOOL NOT NULL DEFAULT FALSE,
|
||||
is_active BOOL NOT NULL,
|
||||
CONSTRAINT filters_staff_id_fk
|
||||
FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
|
||||
|
@ -278,7 +279,7 @@ CREATE TABLE DBPREFIXfilter_conditions(
|
|||
CONSTRAINT filter_conditions_filter_id_fk
|
||||
FOREIGN KEY(filter_id) REFERENCES DBPREFIXfilters(id)
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '')
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '' OR match_mode = 3)
|
||||
);
|
||||
|
||||
CREATE TABLE DBPREFIXfilter_hits(
|
||||
|
|
|
@ -251,6 +251,7 @@ CREATE TABLE DBPREFIXfilters(
|
|||
issued_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
match_action VARCHAR(45) NOT NULL DEFAULT 'replace',
|
||||
match_detail TEXT NOT NULL,
|
||||
handle_if_any BOOL NOT NULL DEFAULT FALSE,
|
||||
is_active BOOL NOT NULL,
|
||||
CONSTRAINT filters_staff_id_fk
|
||||
FOREIGN KEY(staff_id) REFERENCES DBPREFIXstaff(id)
|
||||
|
@ -278,7 +279,7 @@ CREATE TABLE DBPREFIXfilter_conditions(
|
|||
CONSTRAINT filter_conditions_filter_id_fk
|
||||
FOREIGN KEY(filter_id) REFERENCES DBPREFIXfilters(id)
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '')
|
||||
CONSTRAINT filter_conditions_search_check CHECK (search <> '' OR match_mode = 3)
|
||||
);
|
||||
|
||||
CREATE TABLE DBPREFIXfilter_hits(
|
||||
|
|
|
@ -69,6 +69,13 @@
|
|||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<label for="handle_on_any" title="If checked, the filter action will activate if any of the above conditions match an incoming post. Otherwise, all conditions must match">
|
||||
<input type="checkbox" name="handleonany" id="handle_on_any"> Activate if any condition matches</label><br />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th id="detail">Reason</th>
|
||||
<td><textarea name="detail" rows="5" cols="35">{{$.filter.MatchDetail}}</textarea></td>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue