summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/gotosocial/action/server/server.go3
-rw-r--r--internal/api/wellknown/webfinger/webfingerget_test.go2
-rw-r--r--internal/filter/status/status.go31
-rw-r--r--internal/filter/status/status_test.go201
-rw-r--r--internal/processing/account/account.go4
-rw-r--r--internal/processing/account/account_test.go6
-rw-r--r--internal/processing/account/bookmarks.go2
-rw-r--r--internal/processing/account/statuses.go24
-rw-r--r--internal/processing/admin/admin_test.go2
-rw-r--r--internal/processing/common/common.go28
-rw-r--r--internal/processing/common/status.go27
-rw-r--r--internal/processing/conversations/conversations.go38
-rw-r--r--internal/processing/conversations/conversations_test.go3
-rw-r--r--internal/processing/conversations/get.go24
-rw-r--r--internal/processing/conversations/read.go16
-rw-r--r--internal/processing/conversations/update.go53
-rw-r--r--internal/processing/media/media_test.go4
-rw-r--r--internal/processing/polls/poll_test.go4
-rw-r--r--internal/processing/processor.go16
-rw-r--r--internal/processing/processor_test.go2
-rw-r--r--internal/processing/search/util.go2
-rw-r--r--internal/processing/status/status_test.go4
-rw-r--r--internal/processing/stream/statusupdate_test.go3
-rw-r--r--internal/processing/timeline/faved.go3
-rw-r--r--internal/processing/timeline/notification.go35
-rw-r--r--internal/processing/timeline/timeline.go47
-rw-r--r--internal/processing/timeline/timeline_test.go2
-rw-r--r--internal/processing/workers/fromclientapi_test.go8
-rw-r--r--internal/processing/workers/surface.go2
-rw-r--r--internal/processing/workers/surfacenotify.go34
-rw-r--r--internal/processing/workers/surfacetimeline.go60
-rw-r--r--internal/processing/workers/workers.go3
-rw-r--r--internal/typeutils/converter.go3
-rw-r--r--internal/typeutils/internaltofrontend.go57
-rw-r--r--internal/typeutils/internaltofrontend_test.go646
-rw-r--r--internal/webpush/realsender_test.go4
-rw-r--r--testrig/processor.go2
-rw-r--r--testrig/teststructs.go6
38 files changed, 565 insertions, 846 deletions
diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go
index 30e4c28d0..9bbb4bf09 100644
--- a/cmd/gotosocial/action/server/server.go
+++ b/cmd/gotosocial/action/server/server.go
@@ -43,6 +43,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
"code.superseriousbusiness.org/gotosocial/internal/filter/spam"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/httpclient"
@@ -271,6 +272,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
visFilter := visibility.NewFilter(state)
muteFilter := mutes.NewFilter(state)
intFilter := interaction.NewFilter(state)
+ statusFilter := status.NewFilter(state)
spamFilter := spam.NewFilter(state)
federatingDB := federatingdb.New(state, typeConverter, visFilter, intFilter, spamFilter)
transportController := transport.NewController(state, federatingDB, client)
@@ -352,6 +354,7 @@ var Start action.GTSAction = func(ctx context.Context) error {
visFilter,
muteFilter,
intFilter,
+ statusFilter,
)
// Schedule background cleaning tasks.
diff --git a/internal/api/wellknown/webfinger/webfingerget_test.go b/internal/api/wellknown/webfinger/webfingerget_test.go
index 2bdc0f461..395512472 100644
--- a/internal/api/wellknown/webfinger/webfingerget_test.go
+++ b/internal/api/wellknown/webfinger/webfingerget_test.go
@@ -34,6 +34,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/config"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/processing"
@@ -101,6 +102,7 @@ func (suite *WebfingerGetTestSuite) funkifyAccountDomain(host string, accountDom
visibility.NewFilter(&suite.state),
mutes.NewFilter(&suite.state),
interaction.NewFilter(&suite.state),
+ status.NewFilter(&suite.state),
)
suite.webfingerModule = webfinger.New(suite.processor)
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 := &gtsmodel.Filter{
+ ID: id.NewULID(),
+ Title: id.NewULID(),
+ AccountID: requester.ID,
+ Action: gtsmodel.FilterActionWarn,
+ Contexts: gtsmodel.FilterContexts(gtsmodel.FilterContextHome),
+ }
+
+ filterKeyword := &gtsmodel.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))
+}
diff --git a/internal/processing/account/account.go b/internal/processing/account/account.go
index 1e8be372f..e94b7e844 100644
--- a/internal/processing/account/account.go
+++ b/internal/processing/account/account.go
@@ -19,6 +19,7 @@ package account
import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -39,6 +40,7 @@ type Processor struct {
converter *typeutils.Converter
mediaManager *media.Manager
visFilter *visibility.Filter
+ statusFilter *status.Filter
formatter *text.Formatter
federator *federation.Federator
parseMention gtsmodel.ParseMentionFunc
@@ -53,6 +55,7 @@ func New(
mediaManager *media.Manager,
federator *federation.Federator,
visFilter *visibility.Filter,
+ statusFilter *status.Filter,
parseMention gtsmodel.ParseMentionFunc,
) Processor {
return Processor{
@@ -61,6 +64,7 @@ func New(
converter: converter,
mediaManager: mediaManager,
visFilter: visFilter,
+ statusFilter: statusFilter,
formatter: text.NewFormatter(state.DB),
federator: federator,
parseMention: parseMention,
diff --git a/internal/processing/account/account_test.go b/internal/processing/account/account_test.go
index d4fb6ddfb..b322ee771 100644
--- a/internal/processing/account/account_test.go
+++ b/internal/processing/account/account_test.go
@@ -26,6 +26,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -107,8 +108,9 @@ func (suite *AccountStandardTestSuite) SetupTest() {
visFilter := visibility.NewFilter(&suite.state)
mutesFilter := mutes.NewFilter(&suite.state)
- common := common.New(&suite.state, suite.mediaManager, suite.tc, suite.federator, visFilter, mutesFilter)
- suite.accountProcessor = account.New(&common, &suite.state, suite.tc, suite.mediaManager, suite.federator, visFilter, processing.GetParseMentionFunc(&suite.state, suite.federator))
+ statusFilter := status.NewFilter(&suite.state)
+ common := common.New(&suite.state, suite.mediaManager, suite.tc, suite.federator, visFilter, mutesFilter, statusFilter)
+ suite.accountProcessor = account.New(&common, &suite.state, suite.tc, suite.mediaManager, suite.federator, visFilter, statusFilter, processing.GetParseMentionFunc(&suite.state, suite.federator))
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
}
diff --git a/internal/processing/account/bookmarks.go b/internal/processing/account/bookmarks.go
index 7a0ff9915..468c6ad62 100644
--- a/internal/processing/account/bookmarks.go
+++ b/internal/processing/account/bookmarks.go
@@ -74,7 +74,7 @@ func (p *Processor) BookmarksGet(ctx context.Context, requestingAccount *gtsmode
}
// Convert the status.
- item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount, gtsmodel.FilterContextNone)
+ item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
if err != nil {
log.Errorf(ctx, "error converting bookmarked status to api: %s", err)
continue
diff --git a/internal/processing/account/statuses.go b/internal/processing/account/statuses.go
index f0024d489..e55c1e81c 100644
--- a/internal/processing/account/statuses.go
+++ b/internal/processing/account/statuses.go
@@ -96,13 +96,33 @@ func (p *Processor) StatusesGet(
return nil, gtserror.NewErrorInternalError(err)
}
- for _, s := range filtered {
+ for _, status := range filtered {
+ // ...
+ filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ requestingAccount,
+ status,
+ gtsmodel.FilterContextAccount,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error filtering status: %v", err)
+ continue
+ }
+
+ if hide {
+ // Don't show.
+ continue
+ }
+
// Convert filtered statuses to API statuses.
- item, err := p.converter.StatusToAPIStatus(ctx, s, requestingAccount, gtsmodel.FilterContextAccount)
+ item, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
if err != nil {
log.Errorf(ctx, "error convering to api status: %v", err)
continue
}
+
+ // Set any filter results.
+ item.Filtered = filtered
+
items = append(items, item)
}
diff --git a/internal/processing/admin/admin_test.go b/internal/processing/admin/admin_test.go
index 8f2eb23f2..857afcae1 100644
--- a/internal/processing/admin/admin_test.go
+++ b/internal/processing/admin/admin_test.go
@@ -25,6 +25,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -116,6 +117,7 @@ func (suite *AdminStandardTestSuite) SetupTest() {
visibility.NewFilter(&suite.state),
mutes.NewFilter(&suite.state),
interaction.NewFilter(&suite.state),
+ status.NewFilter(&suite.state),
)
testrig.StartWorkers(&suite.state, suite.processor.Workers())
diff --git a/internal/processing/common/common.go b/internal/processing/common/common.go
index bebbdffea..2b3adb9a0 100644
--- a/internal/processing/common/common.go
+++ b/internal/processing/common/common.go
@@ -20,6 +20,7 @@ package common
import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/media"
"code.superseriousbusiness.org/gotosocial/internal/state"
@@ -30,12 +31,13 @@ import (
// common to multiple logical domains of the
// processing subsection of the codebase.
type Processor struct {
- state *state.State
- media *media.Manager
- converter *typeutils.Converter
- federator *federation.Federator
- visFilter *visibility.Filter
- muteFilter *mutes.Filter
+ state *state.State
+ media *media.Manager
+ converter *typeutils.Converter
+ federator *federation.Federator
+ visFilter *visibility.Filter
+ muteFilter *mutes.Filter
+ statusFilter *status.Filter
}
// New returns a new Processor instance.
@@ -46,13 +48,15 @@ func New(
federator *federation.Federator,
visFilter *visibility.Filter,
muteFilter *mutes.Filter,
+ statusFilter *status.Filter,
) Processor {
return Processor{
- state: state,
- media: media,
- converter: converter,
- federator: federator,
- visFilter: visFilter,
- muteFilter: muteFilter,
+ state: state,
+ media: media,
+ converter: converter,
+ federator: federator,
+ visFilter: visFilter,
+ muteFilter: muteFilter,
+ statusFilter: statusFilter,
}
}
diff --git a/internal/processing/common/status.go b/internal/processing/common/status.go
index f5f230e98..2bcf89a02 100644
--- a/internal/processing/common/status.go
+++ b/internal/processing/common/status.go
@@ -27,7 +27,6 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
)
// GetOwnStatus fetches the given status with ID,
@@ -213,7 +212,6 @@ func (p *Processor) GetAPIStatus(
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
target,
requester,
- gtsmodel.FilterContextNone,
)
if err != nil {
err := gtserror.Newf("error converting: %w", err)
@@ -271,22 +269,33 @@ func (p *Processor) GetVisibleAPIStatuses(
continue
}
+ // Check whether status is filtered in context by requesting account.
+ filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ requester,
+ status,
+ filterCtx,
+ )
+ if err != nil {
+ l.Errorf("error filtering: %v", err)
+ continue
+ }
+
+ if hide {
+ continue
+ }
+
// Convert to API status, taking mute / filter into account.
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
status,
requester,
- filterCtx,
)
- if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
+ if err != nil {
l.Errorf("error converting: %v", err)
continue
}
- if apiStatus == nil {
- // Status was
- // filtered out.
- continue
- }
+ // Set filter results on status.
+ apiStatus.Filtered = filtered
// Append converted status to return slice.
apiStatuses = append(apiStatuses, *apiStatus)
diff --git a/internal/processing/conversations/conversations.go b/internal/processing/conversations/conversations.go
index 70fafa437..b80ba659a 100644
--- a/internal/processing/conversations/conversations.go
+++ b/internal/processing/conversations/conversations.go
@@ -23,6 +23,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
@@ -31,10 +32,11 @@ import (
)
type Processor struct {
- state *state.State
- converter *typeutils.Converter
- visFilter *visibility.Filter
- muteFilter *mutes.Filter
+ state *state.State
+ converter *typeutils.Converter
+ visFilter *visibility.Filter
+ muteFilter *mutes.Filter
+ statusFilter *status.Filter
}
func New(
@@ -42,12 +44,14 @@ func New(
converter *typeutils.Converter,
visFilter *visibility.Filter,
muteFilter *mutes.Filter,
+ statusFilter *status.Filter,
) Processor {
return Processor{
- state: state,
- converter: converter,
- visFilter: visFilter,
- muteFilter: muteFilter,
+ state: state,
+ converter: converter,
+ visFilter: visFilter,
+ muteFilter: muteFilter,
+ statusFilter: statusFilter,
}
}
@@ -95,21 +99,3 @@ func (p *Processor) getConversationOwnedBy(
return conversation, nil
}
-
-// getFiltersAndMutes gets the given account's filters and compiled mute list.
-func (p *Processor) getFilters(
- ctx context.Context,
- requestingAccount *gtsmodel.Account,
-) ([]*gtsmodel.Filter, gtserror.WithCode) {
- filters, err := p.state.DB.GetFiltersByAccountID(ctx, requestingAccount.ID)
- if err != nil {
- return nil, gtserror.NewErrorInternalError(
- gtserror.Newf(
- "DB error getting filters for account %s: %w",
- requestingAccount.ID,
- err,
- ),
- )
- }
- return filters, nil
-}
diff --git a/internal/processing/conversations/conversations_test.go b/internal/processing/conversations/conversations_test.go
index 383938564..407623964 100644
--- a/internal/processing/conversations/conversations_test.go
+++ b/internal/processing/conversations/conversations_test.go
@@ -28,6 +28,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
@@ -118,7 +119,7 @@ func (suite *ConversationsTestSuite) SetupTest() {
suite.sentEmails = make(map[string]string)
suite.emailSender = testrig.NewEmailSender("../../../web/template/", suite.sentEmails)
- suite.conversationsProcessor = conversations.New(&suite.state, suite.tc, suite.visFilter, suite.muteFilter)
+ suite.conversationsProcessor = conversations.New(&suite.state, suite.tc, suite.visFilter, suite.muteFilter, status.NewFilter(&suite.state))
testrig.StandardDBSetup(suite.db, nil)
testrig.StandardStorageSetup(suite.storage, "../../../testrig/media")
diff --git a/internal/processing/conversations/get.go b/internal/processing/conversations/get.go
index 5324466c9..cdc0756c3 100644
--- a/internal/processing/conversations/get.go
+++ b/internal/processing/conversations/get.go
@@ -64,17 +64,26 @@ func (p *Processor) GetAll(
items := make([]interface{}, 0, count)
- filters, errWithCode := p.getFilters(ctx, requestingAccount)
- if errWithCode != nil {
- return nil, errWithCode
- }
-
for _, conversation := range conversations {
+ // Check whether status if filtered by local participant in context.
+ filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ requestingAccount,
+ conversation.LastStatus,
+ gtsmodel.FilterContextNotifications,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error filtering status: %v", err)
+ continue
+ }
+
+ if hide {
+ continue
+ }
+
// Convert conversation to frontend API model.
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
conversation,
requestingAccount,
- filters,
)
if err != nil {
log.Errorf(ctx,
@@ -85,6 +94,9 @@ func (p *Processor) GetAll(
continue
}
+ // Set filter results on attached status model.
+ apiConversation.LastStatus.Filtered = filtered
+
// Append conversation to return items.
items = append(items, apiConversation)
}
diff --git a/internal/processing/conversations/read.go b/internal/processing/conversations/read.go
index 4d16a4eeb..c7e4f1acd 100644
--- a/internal/processing/conversations/read.go
+++ b/internal/processing/conversations/read.go
@@ -23,6 +23,7 @@ import (
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
+ "code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/util"
)
@@ -44,20 +45,27 @@ func (p *Processor) Read(
return nil, gtserror.NewErrorInternalError(err)
}
- filters, errWithCode := p.getFilters(ctx, requestingAccount)
- if errWithCode != nil {
- return nil, errWithCode
+ // Check whether status if filtered by local participant in context.
+ filtered, _, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ requestingAccount,
+ conversation.LastStatus,
+ gtsmodel.FilterContextNotifications,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error filtering status: %v", err)
}
apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
conversation,
requestingAccount,
- filters,
)
if err != nil {
err = gtserror.Newf("error converting conversation %s to API representation: %w", id, err)
return nil, gtserror.NewErrorInternalError(err)
}
+ // Set filter results on attached status model.
+ apiConversation.LastStatus.Filtered = filtered
+
return apiConversation, nil
}
diff --git a/internal/processing/conversations/update.go b/internal/processing/conversations/update.go
index cf81d6906..21f1cf915 100644
--- a/internal/processing/conversations/update.go
+++ b/internal/processing/conversations/update.go
@@ -27,7 +27,6 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/id"
"code.superseriousbusiness.org/gotosocial/internal/log"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/util"
)
@@ -158,26 +157,6 @@ func (p *Processor) UpdateConversationsForStatus(ctx context.Context, status *gt
continue
}
- // Convert the conversation to API representation.
- apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
- conversation,
- localAccount,
- nil,
- )
- if err != nil {
- // If the conversation's last status matched a hide filter, skip it.
- // If there was another kind of error, log that and skip it anyway.
- if !errors.Is(err, typeutils.ErrHideStatus) {
- log.Errorf(ctx,
- "error converting conversation %s to API representation for account %s: %v",
- status.ID,
- localAccount.ID,
- err,
- )
- }
- continue
- }
-
// If status was authored by this participant,
// don't bother notifying, they already know!
if status.AccountID == localAccount.ID {
@@ -198,6 +177,38 @@ func (p *Processor) UpdateConversationsForStatus(ctx context.Context, status *gt
continue
}
+ // Check whether status if filtered by local participant in context.
+ filtered, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ localAccount,
+ status,
+ gtsmodel.FilterContextNotifications,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error filtering status: %v", err)
+ continue
+ }
+
+ if hide {
+ continue
+ }
+
+ // Convert the conversation to API representation.
+ apiConversation, err := p.converter.ConversationToAPIConversation(ctx,
+ conversation,
+ localAccount,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error converting conversation %s to API representation for account %s: %v",
+ status.ID,
+ localAccount.ID,
+ err,
+ )
+ continue
+ }
+
+ // Set filter results on attached status model.
+ apiConversation.LastStatus.Filtered = filtered
+
// Generate a notification,
notifications = append(notifications, ConversationNotification{
AccountID: localAccount.ID,
diff --git a/internal/processing/media/media_test.go b/internal/processing/media/media_test.go
index f2462a972..01506cc6f 100644
--- a/internal/processing/media/media_test.go
+++ b/internal/processing/media/media_test.go
@@ -21,6 +21,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/admin"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -85,7 +86,8 @@ func (suite *MediaStandardTestSuite) SetupTest() {
federator := testrig.NewTestFederator(&suite.state, suite.transportController, suite.mediaManager)
visFilter := visibility.NewFilter(&suite.state)
muteFilter := mutes.NewFilter(&suite.state)
- common := common.New(&suite.state, suite.mediaManager, suite.tc, federator, visFilter, muteFilter)
+ statusFilter := status.NewFilter(&suite.state)
+ common := common.New(&suite.state, suite.mediaManager, suite.tc, federator, visFilter, muteFilter, statusFilter)
suite.mediaProcessor = mediaprocessing.New(&common, &suite.state, suite.tc, federator, suite.mediaManager, suite.transportController)
testrig.StandardDBSetup(suite.db, nil)
diff --git a/internal/processing/polls/poll_test.go b/internal/processing/polls/poll_test.go
index 848c3f169..2fd46c5ee 100644
--- a/internal/processing/polls/poll_test.go
+++ b/internal/processing/polls/poll_test.go
@@ -25,6 +25,7 @@ import (
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
@@ -60,7 +61,8 @@ func (suite *PollTestSuite) SetupTest() {
federator := testrig.NewTestFederator(&suite.state, controller, mediaMgr)
suite.visFilter = visibility.NewFilter(&suite.state)
suite.muteFilter = mutes.NewFilter(&suite.state)
- common := common.New(&suite.state, mediaMgr, converter, federator, suite.visFilter, suite.muteFilter)
+ statusFilter := status.NewFilter(&suite.state)
+ common := common.New(&suite.state, mediaMgr, converter, federator, suite.visFilter, suite.muteFilter, statusFilter)
suite.polls = polls.New(&common, &suite.state, converter)
}
diff --git a/internal/processing/processor.go b/internal/processing/processor.go
index c35c807e0..a5cea5da4 100644
--- a/internal/processing/processor.go
+++ b/internal/processing/processor.go
@@ -23,6 +23,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ statusfilter "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
mm "code.superseriousbusiness.org/gotosocial/internal/media"
@@ -193,7 +194,8 @@ func (p *Processor) Workers() *workers.Processor {
return &p.workers
}
-// NewProcessor returns a new Processor.
+// NewProcessor returns
+// a new Processor.
func NewProcessor(
cleaner *cleaner.Cleaner,
subscriptions *subscriptions.Subscriptions,
@@ -207,6 +209,7 @@ func NewProcessor(
visFilter *visibility.Filter,
muteFilter *mutes.Filter,
intFilter *interaction.Filter,
+ statusFilter *statusfilter.Filter,
) *Processor {
parseMentionFunc := GetParseMentionFunc(state, federator)
processor := &Processor{
@@ -221,18 +224,18 @@ func NewProcessor(
//
// Start with sub processors that will
// be required by the workers processor.
- common := common.New(state, mediaManager, converter, federator, visFilter, muteFilter)
- processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)
+ common := common.New(state, mediaManager, converter, federator, visFilter, muteFilter, statusFilter)
+ processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, statusFilter, parseMentionFunc)
processor.media = media.New(&common, state, converter, federator, mediaManager, federator.TransportController())
processor.stream = stream.New(state, oauthServer)
filterCommon := filterCommon.New(state, &processor.stream)
// Instantiate the rest of the sub
// processors + pin them to this struct.
- processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)
+ processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, statusFilter, parseMentionFunc)
processor.admin = admin.New(&common, state, cleaner, subscriptions, federator, converter, mediaManager, federator.TransportController(), emailSender)
processor.application = application.New(state, converter)
- processor.conversations = conversations.New(state, converter, visFilter, muteFilter)
+ processor.conversations = conversations.New(state, converter, visFilter, muteFilter, statusFilter)
processor.fedi = fedi.New(state, &common, converter, federator, visFilter)
processor.filtersv1 = filtersv1.New(state, converter, filterCommon)
processor.filtersv2 = filtersv2.New(state, converter, filterCommon)
@@ -243,7 +246,7 @@ func NewProcessor(
processor.push = push.New(state, converter)
processor.report = report.New(state, converter)
processor.tags = tags.New(state, converter)
- processor.timeline = timeline.New(state, converter, visFilter, muteFilter)
+ processor.timeline = timeline.New(state, converter, visFilter, muteFilter, statusFilter)
processor.search = search.New(state, federator, converter, visFilter)
processor.status = status.New(state, &common, &processor.polls, &processor.interactionRequests, federator, converter, visFilter, intFilter, parseMentionFunc)
processor.user = user.New(state, converter, oauthServer, emailSender)
@@ -261,6 +264,7 @@ func NewProcessor(
converter,
visFilter,
muteFilter,
+ statusFilter,
emailSender,
webPushSender,
&processor.account,
diff --git a/internal/processing/processor_test.go b/internal/processing/processor_test.go
index 847de29cf..3c564b929 100644
--- a/internal/processing/processor_test.go
+++ b/internal/processing/processor_test.go
@@ -28,6 +28,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -133,6 +134,7 @@ func (suite *ProcessingStandardTestSuite) SetupTest() {
visibility.NewFilter(&suite.state),
mutes.NewFilter(&suite.state),
interaction.NewFilter(&suite.state),
+ status.NewFilter(&suite.state),
)
testrig.StartWorkers(&suite.state, suite.processor.Workers())
diff --git a/internal/processing/search/util.go b/internal/processing/search/util.go
index fc105940f..441f3f946 100644
--- a/internal/processing/search/util.go
+++ b/internal/processing/search/util.go
@@ -113,7 +113,7 @@ func (p *Processor) packageStatuses(
continue
}
- apiStatus, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := p.converter.StatusToAPIStatus(ctx, status, requestingAccount)
if err != nil {
log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", status.ID, err)
continue
diff --git a/internal/processing/status/status_test.go b/internal/processing/status/status_test.go
index 091d9716b..d709d435f 100644
--- a/internal/processing/status/status_test.go
+++ b/internal/processing/status/status_test.go
@@ -23,6 +23,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ statusfilter "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -95,8 +96,9 @@ func (suite *StatusStandardTestSuite) SetupTest() {
visFilter := visibility.NewFilter(&suite.state)
muteFilter := mutes.NewFilter(&suite.state)
intFilter := interaction.NewFilter(&suite.state)
+ statusFilter := statusfilter.NewFilter(&suite.state)
- common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter, muteFilter)
+ common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter, muteFilter, statusFilter)
polls := polls.New(&common, &suite.state, suite.typeConverter)
intReqs := interactionrequests.New(&common, &suite.state, suite.typeConverter)
diff --git a/internal/processing/stream/statusupdate_test.go b/internal/processing/stream/statusupdate_test.go
index a3ec0415e..a82348c31 100644
--- a/internal/processing/stream/statusupdate_test.go
+++ b/internal/processing/stream/statusupdate_test.go
@@ -22,7 +22,6 @@ import (
"encoding/json"
"testing"
- "code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/stream"
"code.superseriousbusiness.org/gotosocial/internal/typeutils"
"github.com/stretchr/testify/suite"
@@ -39,7 +38,7 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {
suite.NoError(errWithCode)
editedStatus := suite.testStatuses["remote_account_1_status_1"]
- apiStatus, err := typeutils.NewConverter(&suite.state).StatusToAPIStatus(suite.T().Context(), editedStatus, account, gtsmodel.FilterContextNotifications)
+ apiStatus, err := typeutils.NewConverter(&suite.state).StatusToAPIStatus(suite.T().Context(), editedStatus, account)
suite.NoError(err)
suite.streamProcessor.StatusUpdate(suite.T().Context(), account, apiStatus, stream.TimelineHome)
diff --git a/internal/processing/timeline/faved.go b/internal/processing/timeline/faved.go
index 65b23c702..9218af9c8 100644
--- a/internal/processing/timeline/faved.go
+++ b/internal/processing/timeline/faved.go
@@ -26,7 +26,6 @@ import (
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
- "code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/util"
)
@@ -56,7 +55,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *apiutil.Auth,
continue
}
- apiStatus, err := p.converter.StatusToAPIStatus(ctx, s, authed.Account, gtsmodel.FilterContextNone)
+ apiStatus, err := p.converter.StatusToAPIStatus(ctx, s, authed.Account)
if err != nil {
log.Errorf(ctx, "error convering to api status: %v", err)
continue
diff --git a/internal/processing/timeline/notification.go b/internal/processing/timeline/notification.go
index 784b2b824..b17dda8a7 100644
--- a/internal/processing/timeline/notification.go
+++ b/internal/processing/timeline/notification.go
@@ -31,7 +31,6 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/paging"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/util"
)
@@ -93,8 +92,12 @@ func (p *Processor) NotificationsGet(
continue
}
+ var filtered []apimodel.FilterResult
+
if n.Status != nil {
- // A status is attached, check whether status muted.
+ var hide bool
+
+ // Check whether notification status is muted by requester.
muted, err = p.muteFilter.StatusNotificationsMuted(ctx,
requester,
n.Status,
@@ -107,16 +110,34 @@ func (p *Processor) NotificationsGet(
if muted {
continue
}
+
+ // Check whether notification status is filtered by requester in notifs.
+ filtered, hide, err = p.statusFilter.StatusFilterResultsInContext(ctx,
+ requester,
+ n.Status,
+ gtsmodel.FilterContextNotifications,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error checking status filtering: %v", err)
+ continue
+ }
+
+ if hide {
+ continue
+ }
}
- item, err := p.converter.NotificationToAPINotification(ctx, n, true)
+ item, err := p.converter.NotificationToAPINotification(ctx, n)
if err != nil {
- if !errors.Is(err, typeutils.ErrHideStatus) {
- log.Debugf(ctx, "skipping notification %s because it couldn't be converted to its api representation: %s", n.ID, err)
- }
continue
}
+ if item.Status != nil {
+ // Set filter results on status,
+ // in case any were set above.
+ item.Status.Filtered = filtered
+ }
+
items = append(items, item)
}
@@ -154,7 +175,7 @@ func (p *Processor) NotificationGet(ctx context.Context, account *gtsmodel.Accou
// or mute checking for a notification directly
// fetched by ID. only from timelines etc.
- apiNotif, err := p.converter.NotificationToAPINotification(ctx, notif, false)
+ apiNotif, err := p.converter.NotificationToAPINotification(ctx, notif)
if err != nil {
err := gtserror.Newf("error converting to api model: %w", err)
return nil, gtserror.WrapWithCode(http.StatusInternalServerError, err)
diff --git a/internal/processing/timeline/timeline.go b/internal/processing/timeline/timeline.go
index 64d33e430..06580b3c7 100644
--- a/internal/processing/timeline/timeline.go
+++ b/internal/processing/timeline/timeline.go
@@ -19,13 +19,13 @@ package timeline
import (
"context"
- "errors"
"net/http"
"net/url"
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
timelinepkg "code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
@@ -46,18 +46,26 @@ var (
)
type Processor struct {
- state *state.State
- converter *typeutils.Converter
- visFilter *visibility.Filter
- muteFilter *mutes.Filter
+ state *state.State
+ converter *typeutils.Converter
+ visFilter *visibility.Filter
+ muteFilter *mutes.Filter
+ statusFilter *status.Filter
}
-func New(state *state.State, converter *typeutils.Converter, visFilter *visibility.Filter, muteFilter *mutes.Filter) Processor {
+func New(
+ state *state.State,
+ converter *typeutils.Converter,
+ visFilter *visibility.Filter,
+ muteFilter *mutes.Filter,
+ statusFilter *status.Filter,
+) Processor {
return Processor{
- state: state,
- converter: converter,
- visFilter: visFilter,
- muteFilter: muteFilter,
+ state: state,
+ converter: converter,
+ visFilter: visFilter,
+ muteFilter: muteFilter,
+ statusFilter: statusFilter,
}
}
@@ -116,15 +124,30 @@ func (p *Processor) getStatusTimeline(
return nil, nil
}
+ // Check whether this status is filtered by requester in this context.
+ filters, hide, err := p.statusFilter.StatusFilterResultsInContext(ctx,
+ requester,
+ status,
+ filterCtx,
+ )
+ if err != nil {
+ return nil, err
+ } else if hide {
+ return nil, nil
+ }
+
// Finally, pass status to get converted to API model.
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
status,
requester,
- filterCtx,
)
- if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
+ if err != nil {
return nil, err
}
+
+ // Set any filters on status.
+ apiStatus.Filtered = filters
+
return apiStatus, nil
},
)
diff --git a/internal/processing/timeline/timeline_test.go b/internal/processing/timeline/timeline_test.go
index 01197b767..ce7817df6 100644
--- a/internal/processing/timeline/timeline_test.go
+++ b/internal/processing/timeline/timeline_test.go
@@ -21,6 +21,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/admin"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/processing/timeline"
@@ -64,6 +65,7 @@ func (suite *TimelineStandardTestSuite) SetupTest() {
typeutils.NewConverter(&suite.state),
visibility.NewFilter(&suite.state),
mutes.NewFilter(&suite.state),
+ status.NewFilter(&suite.state),
)
testrig.StandardDBSetup(suite.db, suite.testAccounts)
diff --git a/internal/processing/workers/fromclientapi_test.go b/internal/processing/workers/fromclientapi_test.go
index 4453095fd..7da34ff42 100644
--- a/internal/processing/workers/fromclientapi_test.go
+++ b/internal/processing/workers/fromclientapi_test.go
@@ -212,7 +212,6 @@ func (suite *FromClientAPITestSuite) statusJSON(
ctx,
status,
requestingAccount,
- gtsmodel.FilterContextNone,
)
if err != nil {
suite.FailNow(err.Error())
@@ -236,7 +235,6 @@ func (suite *FromClientAPITestSuite) conversationJSON(
ctx,
conversation,
requestingAccount,
- nil,
)
if err != nil {
suite.FailNow(err.Error())
@@ -344,7 +342,7 @@ func (suite *FromClientAPITestSuite) TestProcessCreateStatusWithNotification() {
suite.FailNow("timed out waiting for new status notification")
}
- apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
+ apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
if err != nil {
suite.FailNow(err.Error())
}
@@ -2031,7 +2029,7 @@ func (suite *FromClientAPITestSuite) TestProcessCreateStatusWithAuthorOnExclusiv
suite.FailNow("timed out waiting for new status notification")
}
- apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
+ apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
if err != nil {
suite.FailNow(err.Error())
}
@@ -2216,7 +2214,7 @@ func (suite *FromClientAPITestSuite) TestProcessUpdateStatusInteractedWith() {
suite.FailNow("timed out waiting for edited status notification")
}
- apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif, false)
+ apiNotif, err := testStructs.TypeConverter.NotificationToAPINotification(ctx, notif)
if err != nil {
suite.FailNow(err.Error())
}
diff --git a/internal/processing/workers/surface.go b/internal/processing/workers/surface.go
index 69758692f..e0e441479 100644
--- a/internal/processing/workers/surface.go
+++ b/internal/processing/workers/surface.go
@@ -20,6 +20,7 @@ package workers
import (
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/processing/conversations"
"code.superseriousbusiness.org/gotosocial/internal/processing/stream"
@@ -40,6 +41,7 @@ type Surface struct {
Stream *stream.Processor
VisFilter *visibility.Filter
MuteFilter *mutes.Filter
+ StatusFilter *status.Filter
EmailSender email.Sender
WebPushSender webpush.Sender
Conversations *conversations.Processor
diff --git a/internal/processing/workers/surfacenotify.go b/internal/processing/workers/surfacenotify.go
index de7e3d95a..15ad79b26 100644
--- a/internal/processing/workers/surfacenotify.go
+++ b/internal/processing/workers/surfacenotify.go
@@ -22,12 +22,12 @@ import (
"errors"
"strings"
+ apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/id"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/util"
"code.superseriousbusiness.org/gotosocial/internal/util/xslices"
)
@@ -727,6 +727,8 @@ func (s *Surface) Notify(
return nil
}
+ var filtered []apimodel.FilterResult
+
if status != nil {
// Check whether status is muted by the target account.
muted, err := s.MuteFilter.StatusNotificationsMuted(ctx,
@@ -741,17 +743,35 @@ func (s *Surface) Notify(
// Don't notify.
return nil
}
+
+ var hide bool
+
+ // Check whether notification status is filtered by requester in notifs.
+ filtered, hide, err = s.StatusFilter.StatusFilterResultsInContext(ctx,
+ targetAccount,
+ status,
+ gtsmodel.FilterContextNotifications,
+ )
+ if err != nil {
+ return gtserror.Newf("error checking status filtering: %w", err)
+ }
+
+ if hide {
+ // Don't notify.
+ return nil
+ }
}
- // Convert the notification to frontend API model for streaming / web push.
- apiNotif, err := s.Converter.NotificationToAPINotification(ctx, notif, true)
- if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
+ // Convert notification to frontend API model for streaming / web push.
+ apiNotif, err := s.Converter.NotificationToAPINotification(ctx, notif)
+ if err != nil {
return gtserror.Newf("error converting notification to api representation: %w", err)
}
- if apiNotif == nil {
- // Filtered.
- return nil
+ if apiNotif.Status != nil {
+ // Set filter results on status,
+ // in case any were set above.
+ apiNotif.Status.Filtered = filtered
}
// Stream notification to the user.
diff --git a/internal/processing/workers/surfacetimeline.go b/internal/processing/workers/surfacetimeline.go
index 5e677c626..b1177cd28 100644
--- a/internal/processing/workers/surfacetimeline.go
+++ b/internal/processing/workers/surfacetimeline.go
@@ -19,7 +19,6 @@ package workers
import (
"context"
- "errors"
"code.superseriousbusiness.org/gotosocial/internal/cache/timeline"
"code.superseriousbusiness.org/gotosocial/internal/gtscontext"
@@ -27,7 +26,6 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/stream"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/util"
)
@@ -350,28 +348,40 @@ func (s *Surface) timelineStatus(
streamType string,
filterCtx gtsmodel.FilterContext,
) bool {
+ // Check whether status is filtered in this context by timeline account.
+ filtered, hide, err := s.StatusFilter.StatusFilterResultsInContext(ctx,
+ account,
+ status,
+ filterCtx,
+ )
+ if err != nil {
+ log.Errorf(ctx, "error filtering status %s: %v", status.URI, err)
+ }
+
+ if hide {
+ // Don't even show to
+ // timeline account.
+ return false
+ }
// Attempt to convert status to frontend API representation,
// this will check whether status is filtered / muted.
apiModel, err := s.Converter.StatusToAPIStatus(ctx,
status,
account,
- filterCtx,
)
- if err != nil && !errors.Is(err, typeutils.ErrHideStatus) {
+ if err != nil {
log.Error(ctx, "error converting status %s to frontend: %v", status.URI, err)
+ } else {
+
+ // Attach any filter results.
+ apiModel.Filtered = filtered
}
// Insert status to timeline cache regardless of
// if API model was succesfully prepared or not.
repeatBoost := timeline.InsertOne(status, apiModel)
- if apiModel == nil {
- // Status was
- // filtered.
- return false
- }
-
if !repeatBoost {
// Only stream if not repeated boost of recent status.
s.Stream.Update(ctx, account, apiModel, streamType)
@@ -683,26 +693,34 @@ func (s *Surface) timelineStreamStatusUpdate(
status *gtsmodel.Status,
streamType string,
) (bool, error) {
-
- // Convert updated database model to frontend model.
- apiStatus, err := s.Converter.StatusToAPIStatus(ctx,
- status,
+ // Check whether status is filtered in this context by timeline account.
+ filtered, hide, err := s.StatusFilter.StatusFilterResultsInContext(ctx,
account,
+ status,
gtsmodel.FilterContextHome,
)
+ if err != nil {
+ return false, gtserror.Newf("error filtering status: %w", err)
+ }
- switch {
- case err == nil:
- // no issue.
-
- case errors.Is(err, typeutils.ErrHideStatus):
- // Don't put this status in the stream.
+ if hide {
+ // Don't even show to
+ // timeline account.
return false, nil
+ }
- default:
+ // Convert updated database model to frontend model.
+ apiStatus, err := s.Converter.StatusToAPIStatus(ctx,
+ status,
+ account,
+ )
+ if err != nil {
return false, gtserror.Newf("error converting status: %w", err)
}
+ // Attach any filter results.
+ apiStatus.Filtered = filtered
+
// The status was updated so stream it to the user.
s.Stream.StatusUpdate(ctx, account, apiStatus, streamType)
diff --git a/internal/processing/workers/workers.go b/internal/processing/workers/workers.go
index 1f4ef465f..67e928db0 100644
--- a/internal/processing/workers/workers.go
+++ b/internal/processing/workers/workers.go
@@ -21,6 +21,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/processing/account"
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
@@ -46,6 +47,7 @@ func New(
converter *typeutils.Converter,
visFilter *visibility.Filter,
muteFilter *mutes.Filter,
+ statusFilter *status.Filter,
emailSender email.Sender,
webPushSender webpush.Sender,
account *account.Processor,
@@ -69,6 +71,7 @@ func New(
Stream: stream,
VisFilter: visFilter,
MuteFilter: muteFilter,
+ StatusFilter: statusFilter,
EmailSender: emailSender,
WebPushSender: webPushSender,
Conversations: conversations,
diff --git a/internal/typeutils/converter.go b/internal/typeutils/converter.go
index 4f3658b0d..789404426 100644
--- a/internal/typeutils/converter.go
+++ b/internal/typeutils/converter.go
@@ -27,7 +27,6 @@ import (
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
- "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/log"
"code.superseriousbusiness.org/gotosocial/internal/state"
@@ -38,7 +37,6 @@ type Converter struct {
defaultAvatars []string
randAvatars sync.Map
visFilter *visibility.Filter
- statusFilter *status.Filter
intFilter *interaction.Filter
randStats atomic.Pointer[apimodel.RandomStats]
}
@@ -48,7 +46,6 @@ func NewConverter(state *state.State) *Converter {
state: state,
defaultAvatars: populateDefaultAvatars(),
visFilter: visibility.NewFilter(state),
- statusFilter: status.NewFilter(state),
intFilter: interaction.NewFilter(state),
}
}
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index a79387c0f..3b5af6579 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -51,10 +51,6 @@ const (
instanceMastodonVersion = "3.5.3"
)
-// ErrHideStatus indicates that a status has
-// been filtered and should not be returned at all.
-var ErrHideStatus = errors.New("hide status")
-
var instanceStatusesSupportedMimeTypes = []string{
string(apimodel.StatusContentTypePlain),
string(apimodel.StatusContentTypeMarkdown),
@@ -850,13 +846,11 @@ func (c *Converter) StatusToAPIStatus(
ctx context.Context,
status *gtsmodel.Status,
requestingAccount *gtsmodel.Account,
- filterCtx gtsmodel.FilterContext,
) (*apimodel.Status, error) {
return c.statusToAPIStatus(
ctx,
status,
requestingAccount,
- filterCtx,
true,
true,
)
@@ -870,7 +864,6 @@ func (c *Converter) statusToAPIStatus(
ctx context.Context,
status *gtsmodel.Status,
requestingAccount *gtsmodel.Account,
- filterCtx gtsmodel.FilterContext,
placeholdAttachments bool,
addPendingNote bool,
) (*apimodel.Status, error) {
@@ -878,7 +871,6 @@ func (c *Converter) statusToAPIStatus(
ctx,
status,
requestingAccount, // Can be nil.
- filterCtx, // Can be empty.
)
if err != nil {
return nil, err
@@ -945,8 +937,7 @@ func (c *Converter) StatusToWebStatus(
s *gtsmodel.Status,
) (*apimodel.WebStatus, error) {
apiStatus, err := c.statusToFrontend(ctx, s,
- nil, // No authed requester.
- gtsmodel.FilterContextNone, // No filters.
+ nil, // No authed requester.
)
if err != nil {
return nil, err
@@ -1115,7 +1106,6 @@ func (c *Converter) statusToFrontend(
ctx context.Context,
status *gtsmodel.Status,
requestingAccount *gtsmodel.Account,
- filterCtx gtsmodel.FilterContext,
) (
*apimodel.Status,
error,
@@ -1123,7 +1113,6 @@ func (c *Converter) statusToFrontend(
apiStatus, err := c.baseStatusToFrontend(ctx,
status,
requestingAccount,
- filterCtx,
)
if err != nil {
return nil, err
@@ -1133,12 +1122,8 @@ func (c *Converter) statusToFrontend(
reblog, err := c.baseStatusToFrontend(ctx,
status.BoostOf,
requestingAccount,
- filterCtx,
)
- if errors.Is(err, ErrHideStatus) {
- // If we'd hide the original status, hide the boost.
- return nil, err
- } else if err != nil {
+ if err != nil {
return nil, gtserror.Newf("error converting boosted status: %w", err)
}
@@ -1165,7 +1150,6 @@ func (c *Converter) baseStatusToFrontend(
ctx context.Context,
status *gtsmodel.Status,
requester *gtsmodel.Account,
- filterCtx gtsmodel.FilterContext,
) (
*apimodel.Status,
error,
@@ -1340,20 +1324,6 @@ func (c *Converter) baseStatusToFrontend(
apiStatus.URL = apiStatus.URI
}
- var hide bool
-
- // Pass the status through any stored filters of requesting account's, in context.
- apiStatus.Filtered, hide, err = c.statusFilter.StatusFilterResultsInContext(ctx,
- requester,
- status,
- filterCtx,
- )
- if err != nil {
- return nil, gtserror.Newf("error filtering status %s: %w", status.URI, err)
- } else if hide {
- return nil, ErrHideStatus
- }
-
return apiStatus, nil
}
@@ -1866,7 +1836,6 @@ func (c *Converter) RelationshipToAPIRelationship(ctx context.Context, r *gtsmod
func (c *Converter) NotificationToAPINotification(
ctx context.Context,
notif *gtsmodel.Notification,
- filter bool,
) (*apimodel.Notification, error) {
// Ensure notif populated.
if err := c.state.DB.PopulateNotification(ctx, notif); err != nil {
@@ -1882,27 +1851,14 @@ func (c *Converter) NotificationToAPINotification(
// Get status that triggered this notif, if set.
var apiStatus *apimodel.Status
if notif.Status != nil {
- var filterCtx gtsmodel.FilterContext
-
- if filter {
- filterCtx = gtsmodel.FilterContextNotifications
- }
-
apiStatus, err = c.StatusToAPIStatus(ctx,
notif.Status,
notif.TargetAccount,
- filterCtx,
)
- if err != nil && !errors.Is(err, ErrHideStatus) {
+ if err != nil {
return nil, gtserror.Newf("error converting status to api: %w", err)
}
- if apiStatus == nil {
- // Notif filtered for this
- // status, nothing to do.
- return nil, err
- }
-
if apiStatus.Reblog != nil {
// Use the actual reblog status
// for the notifications endpoint.
@@ -1926,7 +1882,6 @@ func (c *Converter) ConversationToAPIConversation(
ctx context.Context,
conversation *gtsmodel.Conversation,
requester *gtsmodel.Account,
- filters []*gtsmodel.Filter,
) (*apimodel.Conversation, error) {
apiConversation := &apimodel.Conversation{
ID: conversation.ID,
@@ -1941,9 +1896,8 @@ func (c *Converter) ConversationToAPIConversation(
ctx,
conversation.LastStatus,
requester,
- gtsmodel.FilterContextNotifications,
)
- if err != nil && !errors.Is(err, ErrHideStatus) {
+ if err != nil {
return nil, gtserror.Newf(
"error converting status %s to API representation: %w",
conversation.LastStatus.ID,
@@ -2209,7 +2163,6 @@ func (c *Converter) ReportToAdminAPIReport(ctx context.Context, r *gtsmodel.Repo
ctx,
s,
requestingAccount,
- gtsmodel.FilterContextNone,
true, // Placehold unknown attachments.
// Don't add note about
@@ -2913,7 +2866,6 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
ctx,
req.Status,
requestingAcct,
- gtsmodel.FilterContextNone,
)
if err != nil {
err := gtserror.Newf("error converting interacted status: %w", err)
@@ -2926,7 +2878,6 @@ func (c *Converter) InteractionReqToAPIInteractionReq(
ctx,
req.Reply,
requestingAcct,
- gtsmodel.FilterContextNone,
true, // Placehold unknown attachments.
// Don't add note about pending;
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
index 1fc55acca..8b0d15f10 100644
--- a/internal/typeutils/internaltofrontend_test.go
+++ b/internal/typeutils/internaltofrontend_test.go
@@ -24,12 +24,9 @@ import (
"strings"
"testing"
- apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
"code.superseriousbusiness.org/gotosocial/internal/config"
"code.superseriousbusiness.org/gotosocial/internal/db"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
- "code.superseriousbusiness.org/gotosocial/internal/id"
- "code.superseriousbusiness.org/gotosocial/internal/typeutils"
"code.superseriousbusiness.org/gotosocial/internal/util"
"code.superseriousbusiness.org/gotosocial/testrig"
"github.com/stretchr/testify/suite"
@@ -466,7 +463,7 @@ func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendBloc
func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
testStatus := suite.testStatuses["admin_account_status_1"]
requestingAccount := suite.testAccounts["local_account_1"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -629,7 +626,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendHTMLContentWarning
testStatus.ContentWarning = `<p>First paragraph of content warning</p><h4>Here's the title!</h4><p></p><p>Big boobs<br>Tee hee!<br><br>Some more text<br>And a bunch more<br><br>Hasta la victoria siempre!</p>`
requestingAccount := suite.testAccounts["local_account_1"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -795,7 +792,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendApplicationDeleted
}
requestingAccount := suite.testAccounts["local_account_1"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(ctx, testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(ctx, testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -950,625 +947,11 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendApplicationDeleted
}`, string(b))
}
-// Modify a fixture status into a status that should be filtered,
-// and then filter it, returning the API status or any error from converting it.
-func (suite *InternalToFrontendTestSuite) filteredStatusToFrontend(action gtsmodel.FilterAction, boost bool) (*apimodel.Status, error) {
- ctx := suite.T().Context()
-
- testStatus := suite.testStatuses["admin_account_status_1"]
- testStatus.Content += " fnord"
- testStatus.Text += " fnord"
-
- if boost {
- // Modify a fixture boost into a boost of the above status.
- boostStatus := suite.testStatuses["admin_account_status_4"]
- boostStatus.BoostOf = testStatus
- boostStatus.BoostOfID = testStatus.ID
- testStatus = boostStatus
- }
-
- requestingAccount := suite.testAccounts["local_account_1"]
-
- expectedMatchingFilter := suite.testFilters["local_account_1_filter_1"]
- expectedMatchingFilter.Action = action
-
- err := suite.state.DB.UpdateFilter(ctx, expectedMatchingFilter, "action")
- suite.NoError(err)
-
- return suite.typeconverter.StatusToAPIStatus(
- suite.T().Context(),
- testStatus,
- requestingAccount,
- gtsmodel.FilterContextHome,
- )
-}
-
-// Test that a status which is filtered with a warn filter by the requesting user has `filtered` set correctly.
-func (suite *InternalToFrontendTestSuite) TestWarnFilteredStatusToFrontend() {
- apiStatus, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionWarn, false)
- suite.NoError(err)
-
- b, err := json.MarshalIndent(apiStatus, "", " ")
- suite.NoError(err)
-
- suite.Equal(`{
- "id": "01F8MH75CBF9JFX4ZAD54N0W0R",
- "created_at": "2021-10-20T11:36:45.000Z",
- "edited_at": null,
- "in_reply_to_id": null,
- "in_reply_to_account_id": null,
- "sensitive": false,
- "spoiler_text": "",
- "visibility": "public",
- "language": "en",
- "uri": "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
- "url": "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
- "replies_count": 1,
- "reblogs_count": 0,
- "favourites_count": 1,
- "favourited": true,
- "reblogged": false,
- "muted": false,
- "bookmarked": true,
- "pinned": false,
- "content": "\u003cp\u003ehello world! \u003ca href=\"http://localhost:8080/tags/welcome\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\"\u003e#\u003cspan\u003ewelcome\u003c/span\u003e\u003c/a\u003e ! first post on the instance :rainbow: !\u003c/p\u003e fnord",
- "reblog": null,
- "application": {
- "name": "superseriousbusiness",
- "website": "https://superserious.business"
- },
- "account": {
- "id": "01F8MH17FWEB39HZJ76B6VXSKF",
- "username": "admin",
- "acct": "admin",
- "display_name": "",
- "locked": false,
- "discoverable": true,
- "bot": false,
- "created_at": "2022-05-17T13:10:59.000Z",
- "note": "",
- "url": "http://localhost:8080/@admin",
- "avatar": "",
- "avatar_static": "",
- "header": "http://localhost:8080/assets/default_header.webp",
- "header_static": "http://localhost:8080/assets/default_header.webp",
- "header_description": "Flat gray background (default header).",
- "followers_count": 1,
- "following_count": 1,
- "statuses_count": 4,
- "last_status_at": "2021-10-20",
- "emojis": [],
- "fields": [],
- "enable_rss": true,
- "roles": [
- {
- "id": "admin",
- "name": "admin",
- "color": ""
- }
- ],
- "group": false
- },
- "media_attachments": [
- {
- "id": "01F8MH6NEM8D7527KZAECTCR76",
- "type": "image",
- "url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
- "text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
- "preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
- "remote_url": null,
- "preview_remote_url": null,
- "meta": {
- "original": {
- "width": 1200,
- "height": 630,
- "size": "1200x630",
- "aspect": 1.9047619
- },
- "small": {
- "width": 512,
- "height": 268,
- "size": "512x268",
- "aspect": 1.9104477
- },
- "focus": {
- "x": -0.5,
- "y": 0.5
- }
- },
- "description": "Black and white image of some 50's style text saying: Welcome On Board",
- "blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
- }
- ],
- "mentions": [],
- "tags": [
- {
- "name": "welcome",
- "url": "http://localhost:8080/tags/welcome"
- }
- ],
- "emojis": [
- {
- "shortcode": "rainbow",
- "url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
- "static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
- "visible_in_picker": true,
- "category": "reactions"
- }
- ],
- "card": null,
- "poll": null,
- "text": "hello world! #welcome ! first post on the instance :rainbow: ! fnord",
- "content_type": "text/plain",
- "filtered": [
- {
- "filter": {
- "id": "01HN26VM6KZTW1ANNRVSBMA461",
- "title": "fnord",
- "context": [
- "home",
- "public"
- ],
- "expires_at": null,
- "filter_action": "warn",
- "keywords": [
- {
- "id": "01HN272TAVWAXX72ZX4M8JZ0PS",
- "keyword": "fnord",
- "whole_word": true
- }
- ],
- "statuses": []
- },
- "keyword_matches": [
- "fnord"
- ],
- "status_matches": []
- }
- ],
- "interaction_policy": {
- "can_favourite": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reply": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reblog": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- }
- }
-}`, string(b))
-}
-
-// Test that a status which is filtered with a warn filter by the requesting user has `filtered` set correctly when boosted.
-func (suite *InternalToFrontendTestSuite) TestWarnFilteredBoostToFrontend() {
- apiStatus, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionWarn, true)
- suite.NoError(err)
-
- b, err := json.MarshalIndent(apiStatus, "", " ")
- suite.NoError(err)
-
- suite.Equal(`{
- "id": "01G36SF3V6Y6V5BF9P4R7PQG7G",
- "created_at": "2021-10-20T10:41:37.000Z",
- "edited_at": null,
- "in_reply_to_id": null,
- "in_reply_to_account_id": null,
- "sensitive": false,
- "spoiler_text": "",
- "visibility": "public",
- "language": null,
- "uri": "http://localhost:8080/users/admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G",
- "url": "http://localhost:8080/@admin/statuses/01G36SF3V6Y6V5BF9P4R7PQG7G",
- "replies_count": 0,
- "reblogs_count": 0,
- "favourites_count": 0,
- "favourited": true,
- "reblogged": false,
- "muted": false,
- "bookmarked": true,
- "pinned": false,
- "content": "",
- "reblog": {
- "id": "01F8MH75CBF9JFX4ZAD54N0W0R",
- "created_at": "2021-10-20T11:36:45.000Z",
- "edited_at": null,
- "in_reply_to_id": null,
- "in_reply_to_account_id": null,
- "sensitive": false,
- "spoiler_text": "",
- "visibility": "public",
- "language": "en",
- "uri": "http://localhost:8080/users/admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
- "url": "http://localhost:8080/@admin/statuses/01F8MH75CBF9JFX4ZAD54N0W0R",
- "replies_count": 1,
- "reblogs_count": 0,
- "favourites_count": 1,
- "favourited": true,
- "reblogged": false,
- "muted": false,
- "bookmarked": true,
- "pinned": false,
- "content": "\u003cp\u003ehello world! \u003ca href=\"http://localhost:8080/tags/welcome\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\"\u003e#\u003cspan\u003ewelcome\u003c/span\u003e\u003c/a\u003e ! first post on the instance :rainbow: !\u003c/p\u003e fnord",
- "reblog": null,
- "application": {
- "name": "superseriousbusiness",
- "website": "https://superserious.business"
- },
- "account": {
- "id": "01F8MH1H7YV1Z7D2C8K2730QBF",
- "username": "the_mighty_zork",
- "acct": "the_mighty_zork",
- "display_name": "original zork (he/they)",
- "locked": false,
- "discoverable": true,
- "bot": false,
- "created_at": "2022-05-20T11:09:18.000Z",
- "note": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e",
- "url": "http://localhost:8080/@the_mighty_zork",
- "avatar": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/original/01F8MH58A357CV5K7R7TJMSH6S.jpg",
- "avatar_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/avatar/small/01F8MH58A357CV5K7R7TJMSH6S.webp",
- "avatar_description": "a green goblin looking nasty",
- "avatar_media_id": "01F8MH58A357CV5K7R7TJMSH6S",
- "header": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/original/01PFPMWK2FF0D9WMHEJHR07C3Q.jpg",
- "header_static": "http://localhost:8080/fileserver/01F8MH1H7YV1Z7D2C8K2730QBF/header/small/01PFPMWK2FF0D9WMHEJHR07C3Q.webp",
- "header_description": "A very old-school screenshot of the original team fortress mod for quake",
- "header_media_id": "01PFPMWK2FF0D9WMHEJHR07C3Q",
- "followers_count": 2,
- "following_count": 2,
- "statuses_count": 9,
- "last_status_at": "2024-11-01",
- "emojis": [],
- "fields": [],
- "enable_rss": true,
- "group": false
- },
- "media_attachments": [
- {
- "id": "01F8MH6NEM8D7527KZAECTCR76",
- "type": "image",
- "url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
- "text_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/original/01F8MH6NEM8D7527KZAECTCR76.jpg",
- "preview_url": "http://localhost:8080/fileserver/01F8MH17FWEB39HZJ76B6VXSKF/attachment/small/01F8MH6NEM8D7527KZAECTCR76.webp",
- "remote_url": null,
- "preview_remote_url": null,
- "meta": {
- "original": {
- "width": 1200,
- "height": 630,
- "size": "1200x630",
- "aspect": 1.9047619
- },
- "small": {
- "width": 512,
- "height": 268,
- "size": "512x268",
- "aspect": 1.9104477
- },
- "focus": {
- "x": -0.5,
- "y": 0.5
- }
- },
- "description": "Black and white image of some 50's style text saying: Welcome On Board",
- "blurhash": "LIIE|gRj00WB-;j[t7j[4nWBj[Rj"
- }
- ],
- "mentions": [],
- "tags": [
- {
- "name": "welcome",
- "url": "http://localhost:8080/tags/welcome"
- }
- ],
- "emojis": [
- {
- "shortcode": "rainbow",
- "url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/original/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
- "static_url": "http://localhost:8080/fileserver/01AY6P665V14JJR0AFVRT7311Y/emoji/static/01F8MH9H8E4VG3KDYJR9EGPXCQ.png",
- "visible_in_picker": true,
- "category": "reactions"
- }
- ],
- "card": null,
- "poll": null,
- "text": "hello world! #welcome ! first post on the instance :rainbow: ! fnord",
- "content_type": "text/plain",
- "filtered": [
- {
- "filter": {
- "id": "01HN26VM6KZTW1ANNRVSBMA461",
- "title": "fnord",
- "context": [
- "home",
- "public"
- ],
- "expires_at": null,
- "filter_action": "warn",
- "keywords": [
- {
- "id": "01HN272TAVWAXX72ZX4M8JZ0PS",
- "keyword": "fnord",
- "whole_word": true
- }
- ],
- "statuses": []
- },
- "keyword_matches": [
- "fnord"
- ],
- "status_matches": []
- }
- ],
- "interaction_policy": {
- "can_favourite": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reply": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reblog": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- }
- }
- },
- "application": {
- "name": "superseriousbusiness",
- "website": "https://superserious.business"
- },
- "account": {
- "id": "01F8MH17FWEB39HZJ76B6VXSKF",
- "username": "admin",
- "acct": "admin",
- "display_name": "",
- "locked": false,
- "discoverable": true,
- "bot": false,
- "created_at": "2022-05-17T13:10:59.000Z",
- "note": "",
- "url": "http://localhost:8080/@admin",
- "avatar": "",
- "avatar_static": "",
- "header": "http://localhost:8080/assets/default_header.webp",
- "header_static": "http://localhost:8080/assets/default_header.webp",
- "header_description": "Flat gray background (default header).",
- "followers_count": 1,
- "following_count": 1,
- "statuses_count": 4,
- "last_status_at": "2021-10-20",
- "emojis": [],
- "fields": [],
- "enable_rss": true,
- "roles": [
- {
- "id": "admin",
- "name": "admin",
- "color": ""
- }
- ],
- "group": false
- },
- "media_attachments": [],
- "mentions": [],
- "tags": [],
- "emojis": [],
- "card": null,
- "poll": null,
- "filtered": [
- {
- "filter": {
- "id": "01HN26VM6KZTW1ANNRVSBMA461",
- "title": "fnord",
- "context": [
- "home",
- "public"
- ],
- "expires_at": null,
- "filter_action": "warn",
- "keywords": [
- {
- "id": "01HN272TAVWAXX72ZX4M8JZ0PS",
- "keyword": "fnord",
- "whole_word": true
- }
- ],
- "statuses": []
- },
- "keyword_matches": [
- "fnord"
- ],
- "status_matches": []
- }
- ],
- "interaction_policy": {
- "can_favourite": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reply": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- },
- "can_reblog": {
- "automatic_approval": [
- "public",
- "me"
- ],
- "manual_approval": [],
- "always": [
- "public",
- "me"
- ],
- "with_approval": []
- }
- }
-}`, string(b))
-}
-
-// Test that a status which is filtered with a hide filter by the requesting user results in the ErrHideStatus error.
-func (suite *InternalToFrontendTestSuite) TestHideFilteredStatusToFrontend() {
- _, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionHide, false)
- suite.ErrorIs(err, typeutils.ErrHideStatus)
-}
-
-// Test that a status which is filtered with a hide filter by the requesting user results in the ErrHideStatus error for a boost of that status.
-func (suite *InternalToFrontendTestSuite) TestHideFilteredBoostToFrontend() {
- _, err := suite.filteredStatusToFrontend(gtsmodel.FilterActionHide, true)
- suite.ErrorIs(err, typeutils.ErrHideStatus)
-}
-
-// Test that a hashtag filter for a hashtag in Mastodon HTML content works the way most users would expect.
-func (suite *InternalToFrontendTestSuite) testHashtagFilteredStatusToFrontend(wholeWord bool, boost bool) {
- ctx := suite.T().Context()
-
- testStatus := new(gtsmodel.Status)
- *testStatus = *suite.testStatuses["admin_account_status_1"]
- testStatus.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.typeconverter.StatusToBoost(
- suite.T().Context(),
- testStatus,
- suite.testAccounts["admin_account"],
- "",
- )
- if err != nil {
- suite.FailNow(err.Error())
- }
- testStatus = boost
- }
-
- var err error
-
- requestingAccount := suite.testAccounts["local_account_1"]
-
- filter := &gtsmodel.Filter{
- ID: id.NewULID(),
- Title: id.NewULID(),
- AccountID: requestingAccount.ID,
- Action: gtsmodel.FilterActionWarn,
- Contexts: gtsmodel.FilterContexts(gtsmodel.FilterContextHome),
- }
-
- filterKeyword := &gtsmodel.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)
-
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(
- suite.T().Context(),
- testStatus,
- requestingAccount,
- gtsmodel.FilterContextHome,
- )
- if err != nil {
- suite.FailNow(err.Error())
- }
-
- suite.NotEmpty(apiStatus.Filtered)
-}
-
-func (suite *InternalToFrontendTestSuite) TestHashtagWholeWordFilteredStatusToFrontend() {
- suite.testHashtagFilteredStatusToFrontend(true, false)
-}
-
-func (suite *InternalToFrontendTestSuite) TestHashtagWholeWordFilteredBoostToFrontend() {
- suite.testHashtagFilteredStatusToFrontend(true, true)
-}
-
-func (suite *InternalToFrontendTestSuite) TestHashtagAnywhereFilteredStatusToFrontend() {
- suite.testHashtagFilteredStatusToFrontend(false, false)
-}
-
-func (suite *InternalToFrontendTestSuite) TestHashtagAnywhereFilteredBoostToFrontend() {
- suite.testHashtagFilteredStatusToFrontend(false, true)
-}
-
func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownAttachments() {
testStatus := suite.testStatuses["remote_account_2_status_1"]
requestingAccount := suite.testAccounts["admin_account"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -1895,7 +1278,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendUnknownLanguage()
*testStatus = *suite.testStatuses["admin_account_status_1"]
testStatus.Language = ""
requestingAccount := suite.testAccounts["local_account_1"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -2056,7 +1439,7 @@ func (suite *InternalToFrontendTestSuite) TestStatusToFrontendPartialInteraction
*testStatus = *suite.testStatuses["local_account_1_status_3"]
testStatus.Language = ""
requestingAccount := suite.testAccounts["admin_account"]
- apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount, gtsmodel.FilterContextNone)
+ apiStatus, err := suite.typeconverter.StatusToAPIStatus(suite.T().Context(), testStatus, requestingAccount)
suite.NoError(err)
b, err := json.MarshalIndent(apiStatus, "", " ")
@@ -2169,7 +1552,6 @@ func (suite *InternalToFrontendTestSuite) TestStatusToAPIStatusPendingApproval()
suite.T().Context(),
testStatus,
requestingAccount,
- gtsmodel.FilterContextNone,
)
if err != nil {
suite.FailNow(err.Error())
@@ -3933,10 +3315,9 @@ func (suite *InternalToFrontendTestSuite) TestIntReqToAPI() {
func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
var (
- ctx = suite.T().Context()
- requester = suite.testAccounts["local_account_1"]
- lastStatus = suite.testStatuses["local_account_1_status_1"]
- filters []*gtsmodel.Filter = nil
+ ctx = suite.T().Context()
+ requester = suite.testAccounts["local_account_1"]
+ lastStatus = suite.testStatuses["local_account_1_status_1"]
)
convo := &gtsmodel.Conversation{
@@ -3954,7 +3335,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
ctx,
convo,
requester,
- filters,
)
if err != nil {
suite.FailNow(err.Error())
@@ -4106,10 +3486,9 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPISelfConvo() {
func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
var (
- ctx = suite.T().Context()
- requester = suite.testAccounts["local_account_1"]
- lastStatus = suite.testStatuses["local_account_1_status_1"]
- filters []*gtsmodel.Filter = nil
+ ctx = suite.T().Context()
+ requester = suite.testAccounts["local_account_1"]
+ lastStatus = suite.testStatuses["local_account_1_status_1"]
)
convo := &gtsmodel.Conversation{
@@ -4129,7 +3508,6 @@ func (suite *InternalToFrontendTestSuite) TestConversationToAPI() {
ctx,
convo,
requester,
- filters,
)
if err != nil {
suite.FailNow(err.Error())
diff --git a/internal/webpush/realsender_test.go b/internal/webpush/realsender_test.go
index e11067e1d..52f95ce49 100644
--- a/internal/webpush/realsender_test.go
+++ b/internal/webpush/realsender_test.go
@@ -33,6 +33,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/gtsmodel"
"code.superseriousbusiness.org/gotosocial/internal/media"
@@ -126,6 +127,7 @@ func (suite *RealSenderStandardTestSuite) SetupTest() {
visibility.NewFilter(&suite.state),
mutes.NewFilter(&suite.state),
interaction.NewFilter(&suite.state),
+ status.NewFilter(&suite.state),
)
testrig.StartWorkers(&suite.state, suite.processor.Workers())
@@ -190,7 +192,7 @@ func (suite *RealSenderStandardTestSuite) simulatePushNotification(
}, nil
}
- apiNotif, err := suite.typeconverter.NotificationToAPINotification(ctx, notification, false)
+ apiNotif, err := suite.typeconverter.NotificationToAPINotification(ctx, notification)
suite.NoError(err)
// Send the push notification.
diff --git a/testrig/processor.go b/testrig/processor.go
index 4acb7c648..7d18c1c23 100644
--- a/testrig/processor.go
+++ b/testrig/processor.go
@@ -23,6 +23,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/federation"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/media"
"code.superseriousbusiness.org/gotosocial/internal/processing"
@@ -59,5 +60,6 @@ func NewTestProcessor(
visibility.NewFilter(state),
mutes.NewFilter(state),
interaction.NewFilter(state),
+ status.NewFilter(state),
)
}
diff --git a/testrig/teststructs.go b/testrig/teststructs.go
index a1e241f4e..f002dd079 100644
--- a/testrig/teststructs.go
+++ b/testrig/teststructs.go
@@ -23,6 +23,7 @@ import (
"code.superseriousbusiness.org/gotosocial/internal/email"
"code.superseriousbusiness.org/gotosocial/internal/filter/interaction"
"code.superseriousbusiness.org/gotosocial/internal/filter/mutes"
+ "code.superseriousbusiness.org/gotosocial/internal/filter/status"
"code.superseriousbusiness.org/gotosocial/internal/filter/visibility"
"code.superseriousbusiness.org/gotosocial/internal/processing"
"code.superseriousbusiness.org/gotosocial/internal/processing/common"
@@ -51,6 +52,7 @@ type TestStructs struct {
WebPushSender *WebPushMockSender
TransportController transport.Controller
InteractionFilter *interaction.Filter
+ StatusFilter *status.Filter
}
func SetupTestStructs(
@@ -71,6 +73,7 @@ func SetupTestStructs(
visFilter := visibility.NewFilter(&state)
muteFilter := mutes.NewFilter(&state)
intFilter := interaction.NewFilter(&state)
+ statusFilter := status.NewFilter(&state)
httpClient := NewMockHTTPClient(nil, rMediaPath)
httpClient.TestRemotePeople = NewTestFediPeople()
@@ -90,6 +93,7 @@ func SetupTestStructs(
federator,
visFilter,
muteFilter,
+ statusFilter,
)
processor := processing.NewProcessor(
@@ -105,6 +109,7 @@ func SetupTestStructs(
visFilter,
muteFilter,
intFilter,
+ statusFilter,
)
StartWorkers(&state, processor.Workers())
@@ -122,6 +127,7 @@ func SetupTestStructs(
WebPushSender: webPushSender,
TransportController: transportController,
InteractionFilter: intFilter,
+ StatusFilter: statusFilter,
}
}