diff options
| author | 2024-07-24 13:27:42 +0200 | |
|---|---|---|
| committer | 2024-07-24 12:27:42 +0100 | |
| commit | c9b6220fef01dce80a31436660cd06b4e1db030f (patch) | |
| tree | 5fbade865a920a5ea04fdd63763eca1880d60c5d /internal/processing | |
| parent | [chore] renames the `GTS` caches to `DB` caches (#3127) (diff) | |
| download | gotosocial-c9b6220fef01dce80a31436660cd06b4e1db030f.tar.xz | |
[chore] Add interaction filter to complement existing visibility filter (#3111)
* [chore] Add interaction filter to complement existing visibility filter
* pass in ptr to visibility and interaction filters to Processor{} to ensure shared
* use int constants for for match type, cache db calls in filterctx
* function name typo :innocent:
---------
Co-authored-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/processing')
34 files changed, 357 insertions, 168 deletions
diff --git a/internal/processing/account/account.go b/internal/processing/account/account.go index 65bb40292..d65d7360c 100644 --- a/internal/processing/account/account.go +++ b/internal/processing/account/account.go @@ -38,7 +38,7 @@ type Processor struct {  	state        *state.State  	converter    *typeutils.Converter  	mediaManager *media.Manager -	filter       *visibility.Filter +	visFilter    *visibility.Filter  	formatter    *text.Formatter  	federator    *federation.Federator  	parseMention gtsmodel.ParseMentionFunc @@ -52,7 +52,7 @@ func New(  	converter *typeutils.Converter,  	mediaManager *media.Manager,  	federator *federation.Federator, -	filter *visibility.Filter, +	visFilter *visibility.Filter,  	parseMention gtsmodel.ParseMentionFunc,  ) Processor {  	return Processor{ @@ -60,7 +60,7 @@ func New(  		state:        state,  		converter:    converter,  		mediaManager: mediaManager, -		filter:       filter, +		visFilter:    visFilter,  		formatter:    text.NewFormatter(state.DB),  		federator:    federator,  		parseMention: parseMention, diff --git a/internal/processing/account/bookmarks.go b/internal/processing/account/bookmarks.go index b9ecf0217..d64108d3a 100644 --- a/internal/processing/account/bookmarks.go +++ b/internal/processing/account/bookmarks.go @@ -64,7 +64,7 @@ func (p *Processor) BookmarksGet(ctx context.Context, requestingAccount *gtsmode  			return nil, gtserror.NewErrorInternalError(err) // A real error has occurred.  		} -		visible, err := p.filter.StatusVisible(ctx, requestingAccount, status) +		visible, err := p.visFilter.StatusVisible(ctx, requestingAccount, status)  		if err != nil {  			log.Errorf(ctx, "error checking bookmarked status visibility: %s", err)  			continue diff --git a/internal/processing/account/lists.go b/internal/processing/account/lists.go index 12fbb884b..1d92bee82 100644 --- a/internal/processing/account/lists.go +++ b/internal/processing/account/lists.go @@ -42,7 +42,7 @@ func (p *Processor) ListsGet(ctx context.Context, requestingAccount *gtsmodel.Ac  		return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error: %w", err))  	} -	visible, err := p.filter.AccountVisible(ctx, requestingAccount, targetAccount) +	visible, err := p.visFilter.AccountVisible(ctx, requestingAccount, targetAccount)  	if err != nil {  		return nil, gtserror.NewErrorInternalError(fmt.Errorf("db error: %w", err))  	} diff --git a/internal/processing/account/statuses.go b/internal/processing/account/statuses.go index 593c30e27..2bab812e3 100644 --- a/internal/processing/account/statuses.go +++ b/internal/processing/account/statuses.go @@ -92,7 +92,7 @@ func (p *Processor) StatusesGet(  	// Filtering + serialization process is the same for  	// both pinned status queries and 'normal' ones. -	filtered, err := p.filter.StatusesVisible(ctx, requestingAccount, statuses) +	filtered, err := p.visFilter.StatusesVisible(ctx, requestingAccount, statuses)  	if err != nil {  		return nil, gtserror.NewErrorInternalError(err)  	} diff --git a/internal/processing/admin/admin_test.go b/internal/processing/admin/admin_test.go index 97b055158..3251264b6 100644 --- a/internal/processing/admin/admin_test.go +++ b/internal/processing/admin/admin_test.go @@ -23,6 +23,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/email"  	"github.com/superseriousbusiness/gotosocial/internal/federation" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" @@ -114,6 +115,8 @@ func (suite *AdminStandardTestSuite) SetupTest() {  		suite.mediaManager,  		&suite.state,  		suite.emailSender, +		visibility.NewFilter(&suite.state), +		interaction.NewFilter(&suite.state),  	)  	testrig.StartWorkers(&suite.state, suite.processor.Workers()) diff --git a/internal/processing/common/account.go b/internal/processing/common/account.go index c0daf647d..05e974513 100644 --- a/internal/processing/common/account.go +++ b/internal/processing/common/account.go @@ -55,7 +55,7 @@ func (p *Processor) GetTargetAccountBy(  	}  	// Check whether target account is visible to requesting account. -	visible, err = p.filter.AccountVisible(ctx, requester, target) +	visible, err = p.visFilter.AccountVisible(ctx, requester, target)  	if err != nil {  		return nil, false, gtserror.NewErrorInternalError(err)  	} @@ -241,7 +241,7 @@ func (p *Processor) getVisibleAPIAccounts(  		}  		// Check whether this account is visible to requesting account. -		visible, err := p.filter.AccountVisible(ctx, requester, account) +		visible, err := p.visFilter.AccountVisible(ctx, requester, account)  		if err != nil {  			l.Errorf("error checking account visibility: %v", err)  			continue diff --git a/internal/processing/common/common.go b/internal/processing/common/common.go index 942cecc59..29def3506 100644 --- a/internal/processing/common/common.go +++ b/internal/processing/common/common.go @@ -33,7 +33,7 @@ type Processor struct {  	media     *media.Manager  	converter *typeutils.Converter  	federator *federation.Federator -	filter    *visibility.Filter +	visFilter *visibility.Filter  }  // New returns a new Processor instance. @@ -42,13 +42,13 @@ func New(  	media *media.Manager,  	converter *typeutils.Converter,  	federator *federation.Federator, -	filter *visibility.Filter, +	visFilter *visibility.Filter,  ) Processor {  	return Processor{  		state:     state,  		media:     media,  		converter: converter,  		federator: federator, -		filter:    filter, +		visFilter: visFilter,  	}  } diff --git a/internal/processing/common/status.go b/internal/processing/common/status.go index cce1967b9..3ef643292 100644 --- a/internal/processing/common/status.go +++ b/internal/processing/common/status.go @@ -63,7 +63,7 @@ func (p *Processor) GetTargetStatusBy(  	}  	// Check whether target status is visible to requesting account. -	visible, err = p.filter.StatusVisible(ctx, requester, target) +	visible, err = p.visFilter.StatusVisible(ctx, requester, target)  	if err != nil {  		return nil, false, gtserror.NewErrorInternalError(err)  	} diff --git a/internal/processing/fedi/fedi.go b/internal/processing/fedi/fedi.go index b08f0eefd..52a9d70bf 100644 --- a/internal/processing/fedi/fedi.go +++ b/internal/processing/fedi/fedi.go @@ -32,7 +32,7 @@ type Processor struct {  	state     *state.State  	federator *federation.Federator  	converter *typeutils.Converter -	filter    *visibility.Filter +	visFilter *visibility.Filter  }  // New returns a @@ -42,13 +42,13 @@ func New(  	common *common.Processor,  	converter *typeutils.Converter,  	federator *federation.Federator, -	filter *visibility.Filter, +	visFilter *visibility.Filter,  ) Processor {  	return Processor{  		c:         common,  		state:     state,  		federator: federator,  		converter: converter, -		filter:    filter, +		visFilter: visFilter,  	}  } diff --git a/internal/processing/fedi/status.go b/internal/processing/fedi/status.go index 7c4d4beec..fe07b5a95 100644 --- a/internal/processing/fedi/status.go +++ b/internal/processing/fedi/status.go @@ -68,7 +68,7 @@ func (p *Processor) StatusGet(ctx context.Context, requestedUser string, statusI  		return nil, gtserror.NewErrorNotFound(errors.New(text))  	} -	visible, err := p.filter.StatusVisible(ctx, requestingAcct, status) +	visible, err := p.visFilter.StatusVisible(ctx, requestingAcct, status)  	if err != nil {  		return nil, gtserror.NewErrorInternalError(err)  	} @@ -163,7 +163,7 @@ func (p *Processor) StatusRepliesGet(  	}  	// Reslice replies dropping all those invisible to requester. -	replies, err = p.filter.StatusesVisible(ctx, requestingAcct, replies) +	replies, err = p.visFilter.StatusesVisible(ctx, requestingAcct, replies)  	if err != nil {  		err := gtserror.Newf("error filtering status replies: %w", err)  		return nil, gtserror.NewErrorInternalError(err) diff --git a/internal/processing/processor.go b/internal/processing/processor.go index a07df76e1..5afcf0721 100644 --- a/internal/processing/processor.go +++ b/internal/processing/processor.go @@ -21,6 +21,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/cleaner"  	"github.com/superseriousbusiness/gotosocial/internal/email"  	"github.com/superseriousbusiness/gotosocial/internal/federation" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	mm "github.com/superseriousbusiness/gotosocial/internal/media" @@ -173,11 +174,10 @@ func NewProcessor(  	mediaManager *mm.Manager,  	state *state.State,  	emailSender email.Sender, +	visFilter *visibility.Filter, +	intFilter *interaction.Filter,  ) *Processor { -	var ( -		parseMentionFunc = GetParseMentionFunc(state, federator) -		filter           = visibility.NewFilter(state) -	) +	var parseMentionFunc = GetParseMentionFunc(state, federator)  	processor := &Processor{  		converter:        converter, @@ -191,26 +191,26 @@ func NewProcessor(  	//  	// Start with sub processors that will  	// be required by the workers processor. -	common := common.New(state, mediaManager, converter, federator, filter) -	processor.account = account.New(&common, state, converter, mediaManager, federator, filter, parseMentionFunc) +	common := common.New(state, mediaManager, converter, federator, visFilter) +	processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)  	processor.media = media.New(&common, state, converter, federator, mediaManager, federator.TransportController())  	processor.stream = stream.New(state, oauthServer)  	// Instantiate the rest of the sub  	// processors + pin them to this struct. -	processor.account = account.New(&common, state, converter, mediaManager, federator, filter, parseMentionFunc) +	processor.account = account.New(&common, state, converter, mediaManager, federator, visFilter, parseMentionFunc)  	processor.admin = admin.New(&common, state, cleaner, federator, converter, mediaManager, federator.TransportController(), emailSender) -	processor.conversations = conversations.New(state, converter, filter) -	processor.fedi = fedi.New(state, &common, converter, federator, filter) +	processor.conversations = conversations.New(state, converter, visFilter) +	processor.fedi = fedi.New(state, &common, converter, federator, visFilter)  	processor.filtersv1 = filtersv1.New(state, converter, &processor.stream)  	processor.filtersv2 = filtersv2.New(state, converter, &processor.stream)  	processor.list = list.New(state, converter)  	processor.markers = markers.New(state, converter)  	processor.polls = polls.New(&common, state, converter)  	processor.report = report.New(state, converter) -	processor.timeline = timeline.New(state, converter, filter) -	processor.search = search.New(state, federator, converter, filter) -	processor.status = status.New(state, &common, &processor.polls, federator, converter, filter, parseMentionFunc) +	processor.timeline = timeline.New(state, converter, visFilter) +	processor.search = search.New(state, federator, converter, visFilter) +	processor.status = status.New(state, &common, &processor.polls, federator, converter, visFilter, intFilter, parseMentionFunc)  	processor.user = user.New(state, converter, oauthServer, emailSender)  	// The advanced migrations processor sequences advanced migrations from all other processors. @@ -223,7 +223,7 @@ func NewProcessor(  		state,  		federator,  		converter, -		filter, +		visFilter,  		emailSender,  		&processor.account,  		&processor.media, diff --git a/internal/processing/processor_test.go b/internal/processing/processor_test.go index 767e8b5ef..d0898a98d 100644 --- a/internal/processing/processor_test.go +++ b/internal/processing/processor_test.go @@ -25,6 +25,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/email"  	"github.com/superseriousbusiness/gotosocial/internal/federation" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" @@ -122,7 +123,17 @@ func (suite *ProcessingStandardTestSuite) SetupTest() {  	suite.oauthServer = testrig.NewTestOauthServer(suite.db)  	suite.emailSender = testrig.NewEmailSender("../../web/template/", nil) -	suite.processor = processing.NewProcessor(cleaner.New(&suite.state), suite.typeconverter, suite.federator, suite.oauthServer, suite.mediaManager, &suite.state, suite.emailSender) +	suite.processor = processing.NewProcessor( +		cleaner.New(&suite.state), +		suite.typeconverter, +		suite.federator, +		suite.oauthServer, +		suite.mediaManager, +		&suite.state, +		suite.emailSender, +		visibility.NewFilter(&suite.state), +		interaction.NewFilter(&suite.state), +	)  	testrig.StartWorkers(&suite.state, suite.processor.Workers())  	testrig.StandardDBSetup(suite.db, suite.testAccounts) diff --git a/internal/processing/search/search.go b/internal/processing/search/search.go index 6c0ab2457..18008647c 100644 --- a/internal/processing/search/search.go +++ b/internal/processing/search/search.go @@ -28,15 +28,15 @@ type Processor struct {  	state     *state.State  	federator *federation.Federator  	converter *typeutils.Converter -	filter    *visibility.Filter +	visFilter *visibility.Filter  }  // New returns a new status processor. -func New(state *state.State, federator *federation.Federator, converter *typeutils.Converter, filter *visibility.Filter) Processor { +func New(state *state.State, federator *federation.Federator, converter *typeutils.Converter, visFilter *visibility.Filter) Processor {  	return Processor{  		state:     state,  		federator: federator,  		converter: converter, -		filter:    filter, +		visFilter: visFilter,  	}  } diff --git a/internal/processing/search/util.go b/internal/processing/search/util.go index 190289155..8043affd9 100644 --- a/internal/processing/search/util.go +++ b/internal/processing/search/util.go @@ -103,7 +103,7 @@ func (p *Processor) packageStatuses(  	for _, status := range statuses {  		// Ensure requester can see result status. -		visible, err := p.filter.StatusVisible(ctx, requestingAccount, status) +		visible, err := p.visFilter.StatusVisible(ctx, requestingAccount, status)  		if err != nil {  			err = gtserror.Newf("error checking visibility of status %s for account %s: %w", status.ID, requestingAccount.ID, err)  			return nil, gtserror.NewErrorInternalError(err) diff --git a/internal/processing/status/boost.go b/internal/processing/status/boost.go index 1b410bb0a..d6a0c2457 100644 --- a/internal/processing/status/boost.go +++ b/internal/processing/status/boost.go @@ -66,7 +66,7 @@ func (p *Processor) BoostCreate(  	}  	// Ensure valid boost target for requester. -	boostable, err := p.filter.StatusBoostable(ctx, +	policyResult, err := p.intFilter.StatusBoostable(ctx,  		requester,  		target,  	) @@ -75,12 +75,14 @@ func (p *Processor) BoostCreate(  		return nil, gtserror.NewErrorInternalError(err)  	} -	if !boostable { -		err := gtserror.New("status is not boostable") -		return nil, gtserror.NewErrorNotFound(err) +	if policyResult.Forbidden() { +		const errText = "you do not have permission to boost this status" +		err := gtserror.New(errText) +		return nil, gtserror.NewErrorForbidden(err, errText)  	} -	// Status is visible and boostable. +	// Status is visible and boostable +	// (though maybe pending approval).  	boost, err := p.converter.StatusToBoost(ctx,  		target,  		requester, @@ -90,6 +92,29 @@ func (p *Processor) BoostCreate(  		return nil, gtserror.NewErrorInternalError(err)  	} +	// Derive pendingApproval status. +	var pendingApproval bool +	switch { +	case policyResult.WithApproval(): +		// We're allowed to do +		// this pending approval. +		pendingApproval = true + +	case policyResult.MatchedOnCollection(): +		// We're permitted to do this, but since +		// we matched due to presence in a followers +		// or following collection, we should mark +		// as pending approval and wait for an accept. +		pendingApproval = true + +	case policyResult.Permitted(): +		// We're permitted to do this +		// based on another kind of match. +		pendingApproval = false +	} + +	boost.PendingApproval = &pendingApproval +  	// Store the new boost.  	if err := p.state.DB.PutStatus(ctx, boost); err != nil {  		return nil, gtserror.NewErrorInternalError(err) @@ -184,7 +209,7 @@ func (p *Processor) StatusBoostedBy(ctx context.Context, requestingAccount *gtsm  		targetStatus = boostedStatus  	} -	visible, err := p.filter.StatusVisible(ctx, requestingAccount, targetStatus) +	visible, err := p.visFilter.StatusVisible(ctx, requestingAccount, targetStatus)  	if err != nil {  		err = fmt.Errorf("BoostedBy: error seeing if status %s is visible: %s", targetStatus.ID, err)  		return nil, gtserror.NewErrorNotFound(err) diff --git a/internal/processing/status/context.go b/internal/processing/status/context.go index 013cf4827..9f3a7d089 100644 --- a/internal/processing/status/context.go +++ b/internal/processing/status/context.go @@ -341,7 +341,7 @@ func (p *Processor) ContextGet(  	// Convert ancestors + filter  	// out ones that aren't visible.  	for _, status := range threadContext.ancestors { -		if v, err := p.filter.StatusVisible(ctx, requester, status); err == nil && v { +		if v, err := p.visFilter.StatusVisible(ctx, requester, status); err == nil && v {  			status, err := convert(ctx, status, requester)  			if err == nil {  				apiContext.Ancestors = append(apiContext.Ancestors, *status) @@ -352,7 +352,7 @@ func (p *Processor) ContextGet(  	// Convert descendants + filter  	// out ones that aren't visible.  	for _, status := range threadContext.descendants { -		if v, err := p.filter.StatusVisible(ctx, requester, status); err == nil && v { +		if v, err := p.visFilter.StatusVisible(ctx, requester, status); err == nil && v {  			status, err := convert(ctx, status, requester)  			if err == nil {  				apiContext.Descendants = append(apiContext.Descendants, *status) @@ -453,7 +453,7 @@ func (p *Processor) WebContextGet(  		// Ensure status is actually  		// visible to just anyone, and  		// hide / don't include it if not. -		v, err := p.filter.StatusVisible(ctx, nil, status) +		v, err := p.visFilter.StatusVisible(ctx, nil, status)  		if err != nil || !v {  			if !inReplies {  				// Main thread entry hidden. diff --git a/internal/processing/status/create.go b/internal/processing/status/create.go index e6381eb85..10e19ac43 100644 --- a/internal/processing/status/create.go +++ b/internal/processing/status/create.go @@ -169,6 +169,8 @@ func (p *Processor) Create(  func (p *Processor) processInReplyTo(ctx context.Context, requester *gtsmodel.Account, status *gtsmodel.Status, inReplyToID string) gtserror.WithCode {  	if inReplyToID == "" { +		// Not a reply. +		// Nothing to do.  		return nil  	} @@ -191,6 +193,45 @@ func (p *Processor) processInReplyTo(ctx context.Context, requester *gtsmodel.Ac  		return errWithCode  	} +	// Ensure valid reply target for requester. +	policyResult, err := p.intFilter.StatusReplyable(ctx, +		requester, +		inReplyTo, +	) +	if err != nil { +		err := gtserror.Newf("error seeing if status %s is replyable: %w", status.ID, err) +		return gtserror.NewErrorInternalError(err) +	} + +	if policyResult.Forbidden() { +		const errText = "you do not have permission to reply to this status" +		err := gtserror.New(errText) +		return gtserror.NewErrorForbidden(err, errText) +	} + +	// Derive pendingApproval status. +	var pendingApproval bool +	switch { +	case policyResult.WithApproval(): +		// We're allowed to do +		// this pending approval. +		pendingApproval = true + +	case policyResult.MatchedOnCollection(): +		// We're permitted to do this, but since +		// we matched due to presence in a followers +		// or following collection, we should mark +		// as pending approval and wait for an accept. +		pendingApproval = true + +	case policyResult.Permitted(): +		// We're permitted to do this +		// based on another kind of match. +		pendingApproval = false +	} + +	status.PendingApproval = &pendingApproval +  	// Set status fields from inReplyTo.  	status.InReplyToID = inReplyTo.ID  	status.InReplyTo = inReplyTo diff --git a/internal/processing/status/fave.go b/internal/processing/status/fave.go index 49dacf18d..0f5a72b7d 100644 --- a/internal/processing/status/fave.go +++ b/internal/processing/status/fave.go @@ -72,28 +72,73 @@ func (p *Processor) getFaveableStatus(  }  // FaveCreate adds a fave for the requestingAccount, targeting the given status (no-op if fave already exists). -func (p *Processor) FaveCreate(ctx context.Context, requestingAccount *gtsmodel.Account, targetStatusID string) (*apimodel.Status, gtserror.WithCode) { -	targetStatus, existingFave, errWithCode := p.getFaveableStatus(ctx, requestingAccount, targetStatusID) +func (p *Processor) FaveCreate( +	ctx context.Context, +	requester *gtsmodel.Account, +	targetStatusID string, +) (*apimodel.Status, gtserror.WithCode) { +	status, existingFave, errWithCode := p.getFaveableStatus(ctx, requester, targetStatusID)  	if errWithCode != nil {  		return nil, errWithCode  	}  	if existingFave != nil {  		// Status is already faveed. -		return p.c.GetAPIStatus(ctx, requestingAccount, targetStatus) +		return p.c.GetAPIStatus(ctx, requester, status) +	} + +	// Ensure valid fave target for requester. +	policyResult, err := p.intFilter.StatusLikeable(ctx, +		requester, +		status, +	) +	if err != nil { +		err := gtserror.Newf("error seeing if status %s is likeable: %w", status.ID, err) +		return nil, gtserror.NewErrorInternalError(err) +	} + +	if policyResult.Forbidden() { +		const errText = "you do not have permission to fave this status" +		err := gtserror.New(errText) +		return nil, gtserror.NewErrorForbidden(err, errText) +	} + +	// Derive pendingApproval status. +	var pendingApproval bool +	switch { +	case policyResult.WithApproval(): +		// We're allowed to do +		// this pending approval. +		pendingApproval = true + +	case policyResult.MatchedOnCollection(): +		// We're permitted to do this, but since +		// we matched due to presence in a followers +		// or following collection, we should mark +		// as pending approval and wait for an accept. +		pendingApproval = true + +	case policyResult.Permitted(): +		// We're permitted to do this +		// based on another kind of match. +		pendingApproval = false  	} -	// Create and store a new fave +	status.PendingApproval = &pendingApproval + +	// Create a new fave, marking it +	// as pending approval if necessary.  	faveID := id.NewULID()  	gtsFave := >smodel.StatusFave{  		ID:              faveID, -		AccountID:       requestingAccount.ID, -		Account:         requestingAccount, -		TargetAccountID: targetStatus.AccountID, -		TargetAccount:   targetStatus.Account, -		StatusID:        targetStatus.ID, -		Status:          targetStatus, -		URI:             uris.GenerateURIForLike(requestingAccount.Username, faveID), +		AccountID:       requester.ID, +		Account:         requester, +		TargetAccountID: status.AccountID, +		TargetAccount:   status.Account, +		StatusID:        status.ID, +		Status:          status, +		URI:             uris.GenerateURIForLike(requester.Username, faveID), +		PendingApproval: &pendingApproval,  	}  	if err := p.state.DB.PutStatusFave(ctx, gtsFave); err != nil { @@ -106,11 +151,11 @@ func (p *Processor) FaveCreate(ctx context.Context, requestingAccount *gtsmodel.  		APObjectType:   ap.ActivityLike,  		APActivityType: ap.ActivityCreate,  		GTSModel:       gtsFave, -		Origin:         requestingAccount, -		Target:         targetStatus.Account, +		Origin:         requester, +		Target:         status.Account,  	}) -	return p.c.GetAPIStatus(ctx, requestingAccount, targetStatus) +	return p.c.GetAPIStatus(ctx, requester, status)  }  // FaveRemove removes a fave for the requesting account, targeting the given status (no-op if fave doesn't exist). diff --git a/internal/processing/status/status.go b/internal/processing/status/status.go index 18f8e741a..7e614cc31 100644 --- a/internal/processing/status/status.go +++ b/internal/processing/status/status.go @@ -19,6 +19,7 @@ package status  import (  	"github.com/superseriousbusiness/gotosocial/internal/federation" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/processing/common" @@ -35,7 +36,8 @@ type Processor struct {  	state        *state.State  	federator    *federation.Federator  	converter    *typeutils.Converter -	filter       *visibility.Filter +	visFilter    *visibility.Filter +	intFilter    *interaction.Filter  	formatter    *text.Formatter  	parseMention gtsmodel.ParseMentionFunc @@ -50,7 +52,8 @@ func New(  	polls *polls.Processor,  	federator *federation.Federator,  	converter *typeutils.Converter, -	filter *visibility.Filter, +	visFilter *visibility.Filter, +	intFilter *interaction.Filter,  	parseMention gtsmodel.ParseMentionFunc,  ) Processor {  	return Processor{ @@ -58,7 +61,8 @@ func New(  		state:        state,  		federator:    federator,  		converter:    converter, -		filter:       filter, +		visFilter:    visFilter, +		intFilter:    intFilter,  		formatter:    text.NewFormatter(state.DB),  		parseMention: parseMention,  		polls:        polls, diff --git a/internal/processing/status/status_test.go b/internal/processing/status/status_test.go index 9eba78ec6..f0b22b2c1 100644 --- a/internal/processing/status/status_test.go +++ b/internal/processing/status/status_test.go @@ -21,6 +21,7 @@ import (  	"github.com/stretchr/testify/suite"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/federation" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/media" @@ -89,16 +90,30 @@ func (suite *StatusStandardTestSuite) SetupTest() {  	suite.mediaManager = testrig.NewTestMediaManager(&suite.state)  	suite.federator = testrig.NewTestFederator(&suite.state, suite.tc, suite.mediaManager) -	filter := visibility.NewFilter(&suite.state) +	visFilter := visibility.NewFilter(&suite.state) +	intFilter := interaction.NewFilter(&suite.state)  	testrig.StartTimelines(  		&suite.state, -		filter, +		visFilter,  		suite.typeConverter,  	) -	common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, filter) +	common := common.New(&suite.state, suite.mediaManager, suite.typeConverter, suite.federator, visFilter)  	polls := polls.New(&common, &suite.state, suite.typeConverter) -	suite.status = status.New(&suite.state, &common, &polls, suite.federator, suite.typeConverter, filter, processing.GetParseMentionFunc(&suite.state, suite.federator)) + +	suite.status = status.New( +		&suite.state, +		&common, +		&polls, +		suite.federator, +		suite.typeConverter, +		visFilter, +		intFilter, +		processing.GetParseMentionFunc( +			&suite.state, +			suite.federator, +		), +	)  	testrig.StandardDBSetup(suite.db, suite.testAccounts)  	testrig.StandardStorageSetup(suite.storage, "../../../testrig/media") diff --git a/internal/processing/stream/statusupdate_test.go b/internal/processing/stream/statusupdate_test.go index 2ae3f217b..f6024686b 100644 --- a/internal/processing/stream/statusupdate_test.go +++ b/internal/processing/stream/statusupdate_test.go @@ -133,19 +133,22 @@ func (suite *StatusUpdateTestSuite) TestStreamNotification() {    "interaction_policy": {      "can_favourite": {        "always": [ -        "public" +        "public", +        "me"        ],        "with_approval": []      },      "can_reply": {        "always": [ -        "public" +        "public", +        "me"        ],        "with_approval": []      },      "can_reblog": {        "always": [ -        "public" +        "public", +        "me"        ],        "with_approval": []      } diff --git a/internal/processing/timeline/faved.go b/internal/processing/timeline/faved.go index cd3729465..bb7f03fff 100644 --- a/internal/processing/timeline/faved.go +++ b/internal/processing/timeline/faved.go @@ -45,7 +45,7 @@ func (p *Processor) FavedTimelineGet(ctx context.Context, authed *oauth.Auth, ma  	items := make([]interface{}, 0, count)  	for _, s := range statuses { -		visible, err := p.filter.StatusVisible(ctx, authed.Account, s) +		visible, err := p.visFilter.StatusVisible(ctx, authed.Account, s)  		if err != nil {  			log.Errorf(ctx, "error checking status visibility: %v", err)  			continue diff --git a/internal/processing/timeline/home.go b/internal/processing/timeline/home.go index 8bf8dd428..215000933 100644 --- a/internal/processing/timeline/home.go +++ b/internal/processing/timeline/home.go @@ -62,7 +62,7 @@ func HomeTimelineGrab(state *state.State) timeline.GrabFunction {  }  // HomeTimelineFilter returns a function that satisfies FilterFunction for home timelines. -func HomeTimelineFilter(state *state.State, filter *visibility.Filter) timeline.FilterFunction { +func HomeTimelineFilter(state *state.State, visFilter *visibility.Filter) timeline.FilterFunction {  	return func(ctx context.Context, accountID string, item timeline.Timelineable) (shouldIndex bool, err error) {  		status, ok := item.(*gtsmodel.Status)  		if !ok { @@ -76,7 +76,7 @@ func HomeTimelineFilter(state *state.State, filter *visibility.Filter) timeline.  			return false, err  		} -		timelineable, err := filter.StatusHomeTimelineable(ctx, requestingAccount, status) +		timelineable, err := visFilter.StatusHomeTimelineable(ctx, requestingAccount, status)  		if err != nil {  			err = gtserror.Newf("error checking hometimelineability of status %s for account %s: %w", status.ID, accountID, err)  			return false, err diff --git a/internal/processing/timeline/list.go b/internal/processing/timeline/list.go index 2065256e3..a7f5e9d71 100644 --- a/internal/processing/timeline/list.go +++ b/internal/processing/timeline/list.go @@ -62,7 +62,7 @@ func ListTimelineGrab(state *state.State) timeline.GrabFunction {  }  // ListTimelineFilter returns a function that satisfies FilterFunction for list timelines. -func ListTimelineFilter(state *state.State, filter *visibility.Filter) timeline.FilterFunction { +func ListTimelineFilter(state *state.State, visFilter *visibility.Filter) timeline.FilterFunction {  	return func(ctx context.Context, listID string, item timeline.Timelineable) (shouldIndex bool, err error) {  		status, ok := item.(*gtsmodel.Status)  		if !ok { @@ -82,7 +82,7 @@ func ListTimelineFilter(state *state.State, filter *visibility.Filter) timeline.  			return false, err  		} -		timelineable, err := filter.StatusHomeTimelineable(ctx, requestingAccount, status) +		timelineable, err := visFilter.StatusHomeTimelineable(ctx, requestingAccount, status)  		if err != nil {  			err = gtserror.Newf("error checking hometimelineability of status %s for account %s: %w", status.ID, list.AccountID, err)  			return false, err diff --git a/internal/processing/timeline/notification.go b/internal/processing/timeline/notification.go index 0db4080b9..34e6d865d 100644 --- a/internal/processing/timeline/notification.go +++ b/internal/processing/timeline/notification.go @@ -190,7 +190,7 @@ func (p *Processor) notifVisible(  			return true, nil  		} -		visible, err := p.filter.AccountVisible(ctx, acct, n.OriginAccount) +		visible, err := p.visFilter.AccountVisible(ctx, acct, n.OriginAccount)  		if err != nil {  			return false, err  		} @@ -203,7 +203,7 @@ func (p *Processor) notifVisible(  	// If status is set, ensure it's  	// visible to notif target.  	if n.Status != nil { -		visible, err := p.filter.StatusVisible(ctx, acct, n.Status) +		visible, err := p.visFilter.StatusVisible(ctx, acct, n.Status)  		if err != nil {  			return false, err  		} diff --git a/internal/processing/timeline/public.go b/internal/processing/timeline/public.go index 28062fb2e..dc00688e3 100644 --- a/internal/processing/timeline/public.go +++ b/internal/processing/timeline/public.go @@ -98,7 +98,7 @@ outer:  			// we end up filtering it out or not.  			nextMaxIDValue = s.ID -			timelineable, err := p.filter.StatusPublicTimelineable(ctx, requester, s) +			timelineable, err := p.visFilter.StatusPublicTimelineable(ctx, requester, s)  			if err != nil {  				log.Errorf(ctx, "error checking status visibility: %v", err)  				continue inner diff --git a/internal/processing/timeline/tag.go b/internal/processing/timeline/tag.go index 4320f6adc..811d0bb33 100644 --- a/internal/processing/timeline/tag.go +++ b/internal/processing/timeline/tag.go @@ -128,7 +128,7 @@ func (p *Processor) packageTagResponse(  	compiledMutes := usermute.NewCompiledUserMuteList(mutes)  	for _, s := range statuses { -		timelineable, err := p.filter.StatusTagTimelineable(ctx, requestingAcct, s) +		timelineable, err := p.visFilter.StatusTagTimelineable(ctx, requestingAcct, s)  		if err != nil {  			log.Errorf(ctx, "error checking status visibility: %v", err)  			continue diff --git a/internal/processing/timeline/timeline.go b/internal/processing/timeline/timeline.go index b791791ee..5966fe864 100644 --- a/internal/processing/timeline/timeline.go +++ b/internal/processing/timeline/timeline.go @@ -26,13 +26,13 @@ import (  type Processor struct {  	state     *state.State  	converter *typeutils.Converter -	filter    *visibility.Filter +	visFilter *visibility.Filter  } -func New(state *state.State, converter *typeutils.Converter, filter *visibility.Filter) Processor { +func New(state *state.State, converter *typeutils.Converter, visFilter *visibility.Filter) Processor {  	return Processor{  		state:     state,  		converter: converter, -		filter:    filter, +		visFilter: visFilter,  	}  } diff --git a/internal/processing/workers/fromfediapi_test.go b/internal/processing/workers/fromfediapi_test.go index 705795af4..f08f059ea 100644 --- a/internal/processing/workers/fromfediapi_test.go +++ b/internal/processing/workers/fromfediapi_test.go @@ -45,8 +45,12 @@ func (suite *FromFediAPITestSuite) TestProcessFederationAnnounce() {  	testStructs := suite.SetupTestStructs()  	defer suite.TearDownTestStructs(testStructs) -	boostedStatus := suite.testStatuses["local_account_1_status_1"] -	boostingAccount := suite.testAccounts["remote_account_1"] +	boostedStatus := >smodel.Status{} +	*boostedStatus = *suite.testStatuses["local_account_1_status_1"] + +	boostingAccount := >smodel.Account{} +	*boostingAccount = *suite.testAccounts["remote_account_1"] +  	announceStatus := >smodel.Status{}  	announceStatus.URI = "https://example.org/some-announce-uri"  	announceStatus.BoostOfURI = boostedStatus.URI @@ -64,13 +68,25 @@ func (suite *FromFediAPITestSuite) TestProcessFederationAnnounce() {  		Receiving:      suite.testAccounts["local_account_1"],  		Requesting:     boostingAccount,  	}) -	suite.NoError(err) +	if err != nil { +		suite.FailNow(err.Error()) +	} -	// side effects should be triggered +	// Wait for side effects to trigger:  	// 1. status should have an ID, and be in the database -	suite.NotEmpty(announceStatus.ID) -	_, err = testStructs.State.DB.GetStatusByID(context.Background(), announceStatus.ID) -	suite.NoError(err) +	if !testrig.WaitFor(func() bool { +		if announceStatus.ID == "" { +			return false +		} + +		_, err = testStructs.State.DB.GetStatusByID( +			context.Background(), +			announceStatus.ID, +		) +		return err == nil +	}) { +		suite.FailNow("timed out waiting for announce to be in the database") +	}  	// 2. a notification should exist for the announce  	where := []db.Where{ @@ -89,78 +105,89 @@ func (suite *FromFediAPITestSuite) TestProcessFederationAnnounce() {  	suite.False(*notif.Read)  } -// Todo: fix this test up in interaction policies PR. -// func (suite *FromFediAPITestSuite) TestProcessReplyMention() { -// 	testStructs := suite.SetupTestStructs() -// 	defer suite.TearDownTestStructs(testStructs) - -// 	repliedAccount := suite.testAccounts["local_account_1"] -// 	repliedStatus := suite.testStatuses["local_account_1_status_1"] -// 	replyingAccount := suite.testAccounts["remote_account_1"] - -// 	// Set the replyingAccount's last fetched_at -// 	// date to something recent so no refresh is attempted, -// 	// and ensure it isn't a suspended account. -// 	replyingAccount.FetchedAt = time.Now() -// 	replyingAccount.SuspendedAt = time.Time{} -// 	replyingAccount.SuspensionOrigin = "" -// 	err := testStructs.State.DB.UpdateAccount(context.Background(), -// 		replyingAccount, -// 		"fetched_at", -// 		"suspended_at", -// 		"suspension_origin", -// 	) -// 	suite.NoError(err) - -// 	// Get replying statusable to use from remote test statuses. -// 	const replyingURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552" -// 	replyingStatusable := testrig.NewTestFediStatuses()[replyingURI] -// 	ap.AppendInReplyTo(replyingStatusable, testrig.URLMustParse(repliedStatus.URI)) - -// 	// Open a websocket stream to later test the streamed status reply. -// 	wssStream, errWithCode := testStructs.Processor.Stream().Open(context.Background(), repliedAccount, stream.TimelineHome) -// 	suite.NoError(errWithCode) - -// 	// Send the replied status off to the fedi worker to be further processed. -// 	err = testStructs.Processor.Workers().ProcessFromFediAPI(context.Background(), &messages.FromFediAPI{ -// 		APObjectType:   ap.ObjectNote, -// 		APActivityType: ap.ActivityCreate, -// 		APObject:       replyingStatusable, -// 		Receiving:      repliedAccount, -// 		Requesting:     replyingAccount, -// 	}) -// 	suite.NoError(err) - -// 	// side effects should be triggered -// 	// 1. status should be in the database -// 	replyingStatus, err := testStructs.State.DB.GetStatusByURI(context.Background(), replyingURI) -// 	suite.NoError(err) - -// 	// 2. a notification should exist for the mention -// 	var notif gtsmodel.Notification -// 	err = testStructs.State.DB.GetWhere(context.Background(), []db.Where{ -// 		{Key: "status_id", Value: replyingStatus.ID}, -// 	}, ¬if) -// 	suite.NoError(err) -// 	suite.Equal(gtsmodel.NotificationMention, notif.NotificationType) -// 	suite.Equal(replyingStatus.InReplyToAccountID, notif.TargetAccountID) -// 	suite.Equal(replyingStatus.AccountID, notif.OriginAccountID) -// 	suite.Equal(replyingStatus.ID, notif.StatusID) -// 	suite.False(*notif.Read) - -// 	ctx, _ := context.WithTimeout(context.Background(), time.Second*5) -// 	msg, ok := wssStream.Recv(ctx) -// 	suite.True(ok) - -// 	suite.Equal(stream.EventTypeNotification, msg.Event) -// 	suite.NotEmpty(msg.Payload) -// 	suite.EqualValues([]string{stream.TimelineHome}, msg.Stream) -// 	notifStreamed := &apimodel.Notification{} -// 	err = json.Unmarshal([]byte(msg.Payload), notifStreamed) -// 	suite.NoError(err) -// 	suite.Equal("mention", notifStreamed.Type) -// 	suite.Equal(replyingAccount.ID, notifStreamed.Account.ID) -// } +func (suite *FromFediAPITestSuite) TestProcessReplyMention() { +	testStructs := suite.SetupTestStructs() +	defer suite.TearDownTestStructs(testStructs) + +	repliedAccount := >smodel.Account{} +	*repliedAccount = *suite.testAccounts["local_account_1"] + +	repliedStatus := >smodel.Status{} +	*repliedStatus = *suite.testStatuses["local_account_1_status_1"] + +	replyingAccount := >smodel.Account{} +	*replyingAccount = *suite.testAccounts["remote_account_1"] + +	// Set the replyingAccount's last fetched_at +	// date to something recent so no refresh is attempted, +	// and ensure it isn't a suspended account. +	replyingAccount.FetchedAt = time.Now() +	replyingAccount.SuspendedAt = time.Time{} +	replyingAccount.SuspensionOrigin = "" +	err := testStructs.State.DB.UpdateAccount(context.Background(), +		replyingAccount, +		"fetched_at", +		"suspended_at", +		"suspension_origin", +	) +	suite.NoError(err) + +	// Get replying statusable to use from remote test statuses. +	const replyingURI = "http://fossbros-anonymous.io/users/foss_satan/statuses/106221634728637552" +	replyingStatusable := testrig.NewTestFediStatuses()[replyingURI] +	ap.AppendInReplyTo(replyingStatusable, testrig.URLMustParse(repliedStatus.URI)) + +	// Open a websocket stream to later test the streamed status reply. +	wssStream, errWithCode := testStructs.Processor.Stream().Open(context.Background(), repliedAccount, stream.TimelineHome) +	suite.NoError(errWithCode) + +	// Send the replied status off to the fedi worker to be further processed. +	err = testStructs.Processor.Workers().ProcessFromFediAPI(context.Background(), &messages.FromFediAPI{ +		APObjectType:   ap.ObjectNote, +		APActivityType: ap.ActivityCreate, +		APObject:       replyingStatusable, +		Receiving:      repliedAccount, +		Requesting:     replyingAccount, +	}) +	if err != nil { +		suite.FailNow(err.Error()) +	} + +	// Wait for side effects to trigger: +	// 1. status should be in the database +	var replyingStatus *gtsmodel.Status +	if !testrig.WaitFor(func() bool { +		replyingStatus, err = testStructs.State.DB.GetStatusByURI(context.Background(), replyingURI) +		return err == nil +	}) { +		suite.FailNow("timed out waiting for replying status to be in the database") +	} + +	// 2. a notification should exist for the mention +	var notif gtsmodel.Notification +	err = testStructs.State.DB.GetWhere(context.Background(), []db.Where{ +		{Key: "status_id", Value: replyingStatus.ID}, +	}, ¬if) +	suite.NoError(err) +	suite.Equal(gtsmodel.NotificationMention, notif.NotificationType) +	suite.Equal(replyingStatus.InReplyToAccountID, notif.TargetAccountID) +	suite.Equal(replyingStatus.AccountID, notif.OriginAccountID) +	suite.Equal(replyingStatus.ID, notif.StatusID) +	suite.False(*notif.Read) + +	ctx, _ := context.WithTimeout(context.Background(), time.Second*5) +	msg, ok := wssStream.Recv(ctx) +	suite.True(ok) + +	suite.Equal(stream.EventTypeNotification, msg.Event) +	suite.NotEmpty(msg.Payload) +	suite.EqualValues([]string{stream.TimelineHome}, msg.Stream) +	notifStreamed := &apimodel.Notification{} +	err = json.Unmarshal([]byte(msg.Payload), notifStreamed) +	suite.NoError(err) +	suite.Equal("mention", notifStreamed.Type) +	suite.Equal(replyingAccount.ID, notifStreamed.Account.ID) +}  func (suite *FromFediAPITestSuite) TestProcessFave() {  	testStructs := suite.SetupTestStructs() @@ -305,8 +332,11 @@ func (suite *FromFediAPITestSuite) TestProcessAccountDelete() {  	ctx := context.Background() -	deletedAccount := suite.testAccounts["remote_account_1"] -	receivingAccount := suite.testAccounts["local_account_1"] +	deletedAccount := >smodel.Account{} +	*deletedAccount = *suite.testAccounts["remote_account_1"] + +	receivingAccount := >smodel.Account{} +	*receivingAccount = *suite.testAccounts["local_account_1"]  	// before doing the delete....  	// make local_account_1 and remote_account_1 into mufos diff --git a/internal/processing/workers/surface.go b/internal/processing/workers/surface.go index 1a7dbbfe5..4f6597b9a 100644 --- a/internal/processing/workers/surface.go +++ b/internal/processing/workers/surface.go @@ -36,7 +36,7 @@ type Surface struct {  	State         *state.State  	Converter     *typeutils.Converter  	Stream        *stream.Processor -	Filter        *visibility.Filter +	VisFilter     *visibility.Filter  	EmailSender   email.Sender  	Conversations *conversations.Processor  } diff --git a/internal/processing/workers/surfacenotify_test.go b/internal/processing/workers/surfacenotify_test.go index 937ddeca2..876f69933 100644 --- a/internal/processing/workers/surfacenotify_test.go +++ b/internal/processing/workers/surfacenotify_test.go @@ -42,7 +42,7 @@ func (suite *SurfaceNotifyTestSuite) TestSpamNotifs() {  		State:         testStructs.State,  		Converter:     testStructs.TypeConverter,  		Stream:        testStructs.Processor.Stream(), -		Filter:        visibility.NewFilter(testStructs.State), +		VisFilter:     visibility.NewFilter(testStructs.State),  		EmailSender:   testStructs.EmailSender,  		Conversations: testStructs.Processor.Conversations(),  	} diff --git a/internal/processing/workers/surfacetimeline.go b/internal/processing/workers/surfacetimeline.go index 8ac8293ed..7bd0a51c6 100644 --- a/internal/processing/workers/surfacetimeline.go +++ b/internal/processing/workers/surfacetimeline.go @@ -109,7 +109,7 @@ func (s *Surface) timelineAndNotifyStatusForFollowers(  		// If it's not timelineable, we can just stop early, since lists  		// are prettymuch subsets of the home timeline, so if it shouldn't  		// appear there, it shouldn't appear in lists either. -		timelineable, err := s.Filter.StatusHomeTimelineable( +		timelineable, err := s.VisFilter.StatusHomeTimelineable(  			ctx, follow.Account, status,  		)  		if err != nil { @@ -482,7 +482,7 @@ func (s *Surface) timelineStatusUpdateForFollowers(  		// If it's not timelineable, we can just stop early, since lists  		// are prettymuch subsets of the home timeline, so if it shouldn't  		// appear there, it shouldn't appear in lists either. -		timelineable, err := s.Filter.StatusHomeTimelineable( +		timelineable, err := s.VisFilter.StatusHomeTimelineable(  			ctx, follow.Account, status,  		)  		if err != nil { diff --git a/internal/processing/workers/workers.go b/internal/processing/workers/workers.go index c7f67b025..04010a92e 100644 --- a/internal/processing/workers/workers.go +++ b/internal/processing/workers/workers.go @@ -40,7 +40,7 @@ func New(  	state *state.State,  	federator *federation.Federator,  	converter *typeutils.Converter, -	filter *visibility.Filter, +	visFilter *visibility.Filter,  	emailSender email.Sender,  	account *account.Processor,  	media *media.Processor, @@ -61,7 +61,7 @@ func New(  		State:         state,  		Converter:     converter,  		Stream:        stream, -		Filter:        filter, +		VisFilter:     visFilter,  		EmailSender:   emailSender,  		Conversations: conversations,  	} diff --git a/internal/processing/workers/workers_test.go b/internal/processing/workers/workers_test.go index 3093fd93a..65ed3f6b7 100644 --- a/internal/processing/workers/workers_test.go +++ b/internal/processing/workers/workers_test.go @@ -23,6 +23,7 @@ import (  	"github.com/stretchr/testify/suite"  	"github.com/superseriousbusiness/gotosocial/internal/cleaner"  	"github.com/superseriousbusiness/gotosocial/internal/email" +	"github.com/superseriousbusiness/gotosocial/internal/filter/interaction"  	"github.com/superseriousbusiness/gotosocial/internal/filter/visibility"  	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"  	"github.com/superseriousbusiness/gotosocial/internal/oauth" @@ -160,7 +161,18 @@ func (suite *WorkersTestSuite) SetupTestStructs() *TestStructs {  	oauthServer := testrig.NewTestOauthServer(db)  	emailSender := testrig.NewEmailSender("../../../web/template/", nil) -	processor := processing.NewProcessor(cleaner.New(&state), typeconverter, federator, oauthServer, mediaManager, &state, emailSender) +	processor := processing.NewProcessor( +		cleaner.New(&state), +		typeconverter, +		federator, +		oauthServer, +		mediaManager, +		&state, +		emailSender, +		visibility.NewFilter(&state), +		interaction.NewFilter(&state), +	) +  	testrig.StartWorkers(&state, processor.Workers())  	testrig.StandardDBSetup(db, suite.testAccounts)  | 
