From 66e1ec14aa07e115580afc8e1399677f3b54eeda Mon Sep 17 00:00:00 2001 From: kim Date: Fri, 4 Jul 2025 15:30:39 +0200 Subject: [chore] move status filtering from type converter (#4306) This finalizes the moving status filtering out of the type converter, and into its own `./internal/filter/` subpkg :) Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4306 Co-authored-by: kim Co-committed-by: kim --- internal/processing/workers/fromclientapi_test.go | 8 ++- internal/processing/workers/surface.go | 2 + internal/processing/workers/surfacenotify.go | 34 ++++++++++--- internal/processing/workers/surfacetimeline.go | 60 +++++++++++++++-------- internal/processing/workers/workers.go | 3 ++ 5 files changed, 74 insertions(+), 33 deletions(-) (limited to 'internal/processing/workers') 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, -- cgit v1.2.3