Skip to content

Commit

Permalink
Add wordfilter tests
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmacdonald committed Jun 22, 2024
1 parent c51029b commit e924be3
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 68 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ test-ts:
@cd frontend && pnpm run test

test-go:
@go test $(GO_FLAGS) -race -cover . ./...
@go test $(GO_FLAGS) -race ./...

test-go-cover:
@go test $(GO_FLAGS) -race -coverprofile coverage.out ./...
@go tool cover -html=coverage.out

install_deps:
go install github.com/daixiang0/gci@v0.13.4
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface Filter {
}

export const apiGetFilters = async (abortController?: AbortController) =>
await apiCall<Filter[]>(`/api/filters/query`, 'POST', abortController);
await apiCall<Filter[]>(`/api/filters`, 'GET', abortController);

export const apiCreateFilter = async (filter: Filter) => await apiCall<Filter>(`/api/filters`, 'POST', filter);

Expand Down
36 changes: 35 additions & 1 deletion internal/domain/word_filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package domain

import (
"context"
"errors"
"regexp"
"strings"
"time"
Expand All @@ -20,14 +21,18 @@ type WordFilterRepository interface {
type WordFilterUsecase interface {
Edit(ctx context.Context, user PersonInfo, filterID int64, filter Filter) (Filter, error)
Create(ctx context.Context, user PersonInfo, filter Filter) (Filter, error)
DropFilter(ctx context.Context, filter Filter) error
DropFilter(ctx context.Context, filterID int64) error
GetFilterByID(ctx context.Context, filterID int64) (Filter, error)
GetFilters(ctx context.Context) ([]Filter, error)
Check(query string) []Filter
Import(ctx context.Context) error
AddMessageFilterMatch(ctx context.Context, messageID int64, filterID int64) error
}

type RequestQuery struct {
Query string
}

type FilterAction int

const (
Expand All @@ -36,6 +41,35 @@ const (
Ban
)

func NewFilter(author steamid.SteamID, pattern string, regex bool, action FilterAction, duration string, weight int) (Filter, error) {
now := time.Now()

filter := Filter{
AuthorID: author,
Pattern: pattern,
IsRegex: regex,
IsEnabled: true,
Action: action,
Duration: duration,
Regex: nil,
TriggerCount: 0,
Weight: weight,
CreatedOn: now,
UpdatedOn: now,
}

if regex {
compiled, errRegex := regexp.Compile(pattern)
if errRegex != nil {
return Filter{}, errors.Join(errRegex, ErrInvalidRegex)
}

filter.Regex = compiled
}

return filter, nil
}

type Filter struct {
FilterID int64 `json:"filter_id"`
AuthorID steamid.SteamID `json:"author_id"`
Expand Down
4 changes: 4 additions & 0 deletions internal/test/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -81,6 +82,8 @@ var (
)

func TestMain(m *testing.M) {
slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil)))

testCtx, cancel := context.WithTimeout(context.Background(), time.Minute*2)
defer cancel()

Expand Down Expand Up @@ -196,6 +199,7 @@ func testRouter() *gin.Engine {
config.NewConfigHandler(router, configUC, authUC, app.Version())
report.NewReportHandler(router, reportUC, authUC)
appeal.NewAppealHandler(router, appealUC, banSteamUC, configUC, personUC, discordUC, authUC)
wordfilter.NewWordFilterHandler(router, configUC, wordFilterUC, chatUC, authUC)

return router
}
Expand Down
8 changes: 1 addition & 7 deletions internal/test/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,10 @@ func TestReportPermissions(t *testing.T) {
},
{
path: "/api/reports/user",
method: http.MethodPost,
method: http.MethodGet,
code: http.StatusForbidden,
levels: authed,
},
{
path: "/api/report/1/state",
method: http.MethodPost,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/reports",
method: http.MethodPost,
Expand Down
109 changes: 109 additions & 0 deletions internal/test/wordfilter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package test_test

import (
"fmt"
"net/http"
"testing"

"github.com/leighmacdonald/gbans/internal/domain"
"github.com/stretchr/testify/require"
)

func TestWordFilter(t *testing.T) {
router := testRouter()
moderator := getModerator()
creds := loginUser(moderator)

// Shouldn't be filters already
var filters []domain.Filter
testEndpointWithReceiver(t, router, http.MethodGet, "/api/filters", nil, http.StatusOK, creds, &filters)
require.Empty(t, filters)

// Create a filter
req, errReq := domain.NewFilter(moderator.SteamID, "test", true, domain.Mute, "1d", 1)
require.NoError(t, errReq)

var created domain.Filter
testEndpointWithReceiver(t, router, http.MethodPost, "/api/filters", req, http.StatusOK, creds, &created)
require.Positive(t, created.FilterID)

// Check it was added
testEndpointWithReceiver(t, router, http.MethodGet, "/api/filters", req, http.StatusOK, creds, &filters)
require.NotEmpty(t, filters)

// Edit it
edit := filters[0]
edit.Pattern = "blah"
edit.IsRegex = false

var edited domain.Filter
testEndpointWithReceiver(t, router, http.MethodPost, fmt.Sprintf("/api/filters/%d", edit.FilterID), edit, http.StatusOK, creds, &edited)
require.Equal(t, edit.FilterID, edited.FilterID)
require.Equal(t, edit.AuthorID, edited.AuthorID)
require.Equal(t, edit.Pattern, edited.Pattern)
require.Equal(t, edit.IsRegex, edited.IsRegex)
require.Equal(t, edit.IsEnabled, edited.IsEnabled)
require.Equal(t, edit.Action, edited.Action)
require.Equal(t, edit.Duration, edited.Duration)
require.Equal(t, edit.TriggerCount, edited.TriggerCount)
require.Equal(t, edit.Weight, edited.Weight)
require.NotEqual(t, edit.UpdatedOn, edited.UpdatedOn)

// Match it
var matched []domain.Filter
testEndpointWithReceiver(t, router, http.MethodPost, "/api/filter_match", domain.RequestQuery{Query: edited.Pattern}, http.StatusOK, creds, &matched)
require.NotEmpty(t, matched)
require.Equal(t, matched[0].FilterID, edited.FilterID)

// Delete it
testEndpoint(t, router, http.MethodDelete, fmt.Sprintf("/api/filters/%d", edit.FilterID), req, http.StatusOK, creds)

// Shouldn't match now
testEndpointWithReceiver(t, router, http.MethodPost, "/api/filter_match", domain.RequestQuery{Query: edited.Pattern}, http.StatusOK, creds, &matched)
require.Empty(t, matched)

// Make sure it was deleted
testEndpointWithReceiver(t, router, http.MethodGet, "/api/filters", nil, http.StatusOK, creds, &filters)
require.Empty(t, filters)
}

func TestWordFilterPermissions(t *testing.T) {
testPermissions(t, testRouter(), []permTestValues{
{
path: "/api/filters/query",
method: http.MethodPost,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/filters/state",
method: http.MethodGet,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/filters",
method: http.MethodPost,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/filters/1",
method: http.MethodPost,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/filters/1",
method: http.MethodDelete,
code: http.StatusForbidden,
levels: moderators,
},
{
path: "/api/filter_match",
method: http.MethodPost,
code: http.StatusForbidden,
levels: moderators,
},
})
}
12 changes: 6 additions & 6 deletions internal/wordfilter/word_filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ func (f *WordFilters) Import(filters []domain.Filter) {
f.wordFilters = filters
}

func (f *WordFilters) Add(filter *domain.Filter) {
func (f *WordFilters) Add(filter domain.Filter) {
f.Lock()
f.wordFilters = append(f.wordFilters, *filter)
f.wordFilters = append(f.wordFilters, filter)
f.Unlock()
}

// Match checks to see if the body of text contains a known filtered word
// It will only return the first matched filter found.
func (f *WordFilters) Match(body string) (string, *domain.Filter) {
func (f *WordFilters) Match(body string) (string, domain.Filter, bool) {
if body == "" {
return "", nil
return "", domain.Filter{}, false
}

words := strings.Split(strings.ToLower(body), " ")
Expand All @@ -47,12 +47,12 @@ func (f *WordFilters) Match(body string) (string, *domain.Filter) {
for _, filter := range f.wordFilters {
for _, word := range words {
if filter.IsEnabled && filter.Match(word) {
return word, &filter
return word, filter, true
}
}
}

return "", nil
return "", domain.Filter{}, false
}

func (f *WordFilters) Remove(filterID int64) {
Expand Down
Loading

0 comments on commit e924be3

Please sign in to comment.