diff options
Diffstat (limited to 'internal/filter')
| -rw-r--r-- | internal/filter/status/status.go | 31 | ||||
| -rw-r--r-- | internal/filter/status/status_test.go | 201 |
2 files changed, 227 insertions, 5 deletions
diff --git a/internal/filter/status/status.go b/internal/filter/status/status.go index 5f997129d..e38131ae3 100644 --- a/internal/filter/status/status.go +++ b/internal/filter/status/status.go @@ -25,6 +25,7 @@ import ( apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model" "code.superseriousbusiness.org/gotosocial/internal/cache" + "code.superseriousbusiness.org/gotosocial/internal/gtscontext" "code.superseriousbusiness.org/gotosocial/internal/gtserror" "code.superseriousbusiness.org/gotosocial/internal/gtsmodel" ) @@ -159,6 +160,31 @@ func (f *Filter) getStatusFilterResults( return results, nil } + // Check if status is boost. + if status.BoostOfID != "" { + if status.BoostOf == nil { + var err error + + // Ensure original status is loaded on boost. + status.BoostOf, err = f.state.DB.GetStatusByID( + gtscontext.SetBarebones(ctx), + status.BoostOfID, + ) + if err != nil { + return results, gtserror.Newf("error getting boosted status of %s: %w", status.URI, err) + } + } + + // From here look at details + // for original boosted status. + status = status.BoostOf + } + + // For proper status filtering we need all fields populated. + if err := f.state.DB.PopulateStatus(ctx, status); err != nil { + return results, gtserror.Newf("error populating status: %w", err) + } + // Get the string fields status is // filterable on for keyword matching. fields := getFilterableFields(status) @@ -169,11 +195,6 @@ func (f *Filter) getStatusFilterResults( return results, gtserror.Newf("error getting account filters: %w", err) } - // For proper status filtering we need all fields populated. - if err := f.state.DB.PopulateStatus(ctx, status); err != nil { - return results, gtserror.Newf("error populating status: %w", err) - } - // Generate result for each filter. for _, filter := range filters { diff --git a/internal/filter/status/status_test.go b/internal/filter/status/status_test.go new file mode 100644 index 000000000..e81b7d34e --- /dev/null +++ b/internal/filter/status/status_test.go @@ -0,0 +1,201 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package status_test + +import ( + "testing" + + apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model" + "code.superseriousbusiness.org/gotosocial/internal/filter/status" + "code.superseriousbusiness.org/gotosocial/internal/gtsmodel" + "code.superseriousbusiness.org/gotosocial/internal/id" + "code.superseriousbusiness.org/gotosocial/internal/state" + "code.superseriousbusiness.org/gotosocial/internal/typeutils" + "code.superseriousbusiness.org/gotosocial/testrig" + "github.com/stretchr/testify/suite" +) + +type StatusFilterTestSuite struct { + suite.Suite + + state state.State + filter *status.Filter + converter *typeutils.Converter + + testAccounts map[string]*gtsmodel.Account + testFilters map[string]*gtsmodel.Filter + testStatuses map[string]*gtsmodel.Status +} + +func (suite *StatusFilterTestSuite) SetupTest() { + suite.state.Caches.Init() + + testrig.InitTestConfig() + testrig.InitTestLog() + + db := testrig.NewTestDB(&suite.state) + suite.state.DB = db + + suite.filter = status.NewFilter(&suite.state) + + suite.converter = typeutils.NewConverter(&suite.state) + + suite.testAccounts = testrig.NewTestAccounts() + suite.testFilters = testrig.NewTestFilters() + suite.testStatuses = testrig.NewTestStatuses() + + testrig.StandardDBSetup(suite.state.DB, nil) +} + +func (suite *StatusFilterTestSuite) TearDownTest() { + testrig.StandardDBTeardown(suite.state.DB) + testrig.StopWorkers(&suite.state) +} + +func (suite *StatusFilterTestSuite) TestHideFilteredStatus() { + filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionHide, false) + suite.NoError(err) + suite.True(hide) + suite.Empty(filtered) +} + +func (suite *StatusFilterTestSuite) TestWarnFilteredStatus() { + filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionWarn, false) + suite.NoError(err) + suite.False(hide) + suite.NotEmpty(filtered) +} + +func (suite *StatusFilterTestSuite) TestHideFilteredBoost() { + filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionHide, true) + suite.NoError(err) + suite.True(hide) + suite.Empty(filtered) +} + +func (suite *StatusFilterTestSuite) TestWarnFilteredBoost() { + filtered, hide, err := suite.testFilterStatus(gtsmodel.FilterActionWarn, true) + suite.NoError(err) + suite.False(hide) + suite.NotEmpty(filtered) +} + +func (suite *StatusFilterTestSuite) TestHashtagWholewordStatusFiltered() { + suite.testFilteredStatusWithHashtag(true, false) +} + +func (suite *StatusFilterTestSuite) TestHashtagWholewordBoostFiltered() { + suite.testFilteredStatusWithHashtag(true, true) +} + +func (suite *StatusFilterTestSuite) TestHashtagAnywhereStatusFiltered() { + suite.testFilteredStatusWithHashtag(false, false) +} + +func (suite *StatusFilterTestSuite) TestHashtagAnywhereBoostFiltered() { + suite.testFilteredStatusWithHashtag(false, true) +} + +func (suite *StatusFilterTestSuite) testFilterStatus(action gtsmodel.FilterAction, boost bool) ([]apimodel.FilterResult, bool, error) { + ctx := suite.T().Context() + + status := suite.testStatuses["admin_account_status_1"] + status.Content += " fnord" + status.Text += " fnord" + + if boost { + // Modify a fixture boost into a boost of the above status. + boost := suite.testStatuses["admin_account_status_4"] + boost.BoostOf = status + boost.BoostOfID = status.ID + status = boost + } + + requester := suite.testAccounts["local_account_1"] + + filter := suite.testFilters["local_account_1_filter_1"] + filter.Action = action + + err := suite.state.DB.UpdateFilter(ctx, filter, "action") + suite.NoError(err) + + return suite.filter.StatusFilterResultsInContext(ctx, + requester, + status, + gtsmodel.FilterContextHome, + ) +} + +func (suite *StatusFilterTestSuite) testFilteredStatusWithHashtag(wholeword, boost bool) { + ctx := suite.T().Context() + + status := new(gtsmodel.Status) + *status = *suite.testStatuses["admin_account_status_1"] + status.Content = `<p>doggo doggin' it</p><p><a href="https://example.test/tags/dogsofmastodon" class="mention hashtag" rel="tag nofollow noreferrer noopener" target="_blank">#<span>dogsofmastodon</span></a></p>` + + if boost { + boost, err := suite.converter.StatusToBoost( + suite.T().Context(), + status, + suite.testAccounts["admin_account"], + "", + ) + suite.NoError(err) + status = boost + } + + var err error + + requester := suite.testAccounts["local_account_1"] + + filter := >smodel.Filter{ + ID: id.NewULID(), + Title: id.NewULID(), + AccountID: requester.ID, + Action: gtsmodel.FilterActionWarn, + Contexts: gtsmodel.FilterContexts(gtsmodel.FilterContextHome), + } + + filterKeyword := >smodel.FilterKeyword{ + ID: id.NewULID(), + FilterID: filter.ID, + Keyword: "#dogsofmastodon", + WholeWord: &wholeword, + } + + filter.KeywordIDs = []string{filterKeyword.ID} + + err = suite.state.DB.PutFilterKeyword(ctx, filterKeyword) + suite.NoError(err) + + err = suite.state.DB.PutFilter(ctx, filter) + suite.NoError(err) + + filtered, hide, err := suite.filter.StatusFilterResultsInContext(ctx, + requester, + status, + gtsmodel.FilterContextHome, + ) + suite.NoError(err) + suite.False(hide) + suite.NotEmpty(filtered) +} + +func TestStatusFilterTestSuite(t *testing.T) { + suite.Run(t, new(StatusFilterTestSuite)) +} |
