[bugfix] Move follow.show_reblogs check further up to avoid showing unwanted reblogs in home timeline (#2234)

This commit is contained in:
tobi 2023-09-29 10:39:35 +02:00 committed by GitHub
parent 2a9927dfdc
commit b6b8f82c87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 53 additions and 27 deletions

View file

@ -91,9 +91,13 @@ func (s *surface) timelineAndNotifyStatusForFollowers(
) )
for _, follow := range follows { for _, follow := range follows {
// Do an initial rough-grained check to see if the // Check to see if the status is timelineable for this follower,
// status is timelineable for this follower at all // taking account of its visibility, who it replies to, and, if
// based on its visibility and who it replies to etc. // it's a reblog, whether follower account wants to see reblogs.
//
// 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.filter.StatusHomeTimelineable(
ctx, follow.Account, status, ctx, follow.Account, status,
) )
@ -107,17 +111,6 @@ func (s *surface) timelineAndNotifyStatusForFollowers(
continue continue
} }
if boost && !*follow.ShowReblogs {
// Status is a boost, but the owner of
// this follow doesn't want to see boosts
// from this account. We can safely skip
// everything, then, because we also know
// that the follow owner won't want to be
// have the status put in any list timelines,
// or be notified about the status either.
continue
}
// Add status to any relevant lists // Add status to any relevant lists
// for this follow, if applicable. // for this follow, if applicable.
s.listTimelineStatusForFollow( s.listTimelineStatusForFollow(

View file

@ -19,10 +19,12 @@
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"time" "time"
"github.com/superseriousbusiness/gotosocial/internal/cache" "github.com/superseriousbusiness/gotosocial/internal/cache"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext" "github.com/superseriousbusiness/gotosocial/internal/gtscontext"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@ -169,24 +171,23 @@ func (f *Filter) isStatusHomeTimelineable(ctx context.Context, owner *gtsmodel.A
// a status thread *including* the owner, or a conversation thread between // a status thread *including* the owner, or a conversation thread between
// accounts the timeline owner follows. // accounts the timeline owner follows.
if status.Visibility == gtsmodel.VisibilityFollowersOnly || // Ensure owner follows author.
status.Visibility == gtsmodel.VisibilityMutualsOnly { follow, err := f.state.DB.GetFollow(ctx,
// Followers/mutuals only post that already passed the status
// visibility check, (i.e. we follow / mutuals with author).
return true, nil
}
// Ensure owner follows author of public/unlocked status.
follow, err := f.state.DB.IsFollowing(ctx,
owner.ID, owner.ID,
status.AccountID, status.AccountID,
) )
if err != nil { if err != nil && !errors.Is(err, db.ErrNoEntries) {
return false, gtserror.Newf("error checking follow %s->%s: %w", owner.ID, status.AccountID, err) return false, gtserror.Newf("error retrieving follow %s->%s: %w", owner.ID, status.AccountID, err)
} }
if !follow { if follow == nil {
log.Trace(ctx, "ignoring visible status from unfollowed author") log.Trace(ctx, "ignoring status from unfollowed author")
return false, nil
}
if status.BoostOfID != "" && !*follow.ShowReblogs {
// Status is a boost, but the owner of this follow
// doesn't want to see boosts from this account.
return false, nil return false, nil
} }

View file

@ -55,6 +55,38 @@ func (suite *StatusStatusHomeTimelineableTestSuite) TestFollowingStatusHomeTimel
suite.True(timelineable) suite.True(timelineable)
} }
func (suite *StatusStatusHomeTimelineableTestSuite) TestFollowingBoostedStatusHomeTimelineable() {
ctx := context.Background()
testStatus := suite.testStatuses["admin_account_status_4"]
testAccount := suite.testAccounts["local_account_1"]
timelineable, err := suite.filter.StatusHomeTimelineable(ctx, testAccount, testStatus)
suite.NoError(err)
suite.True(timelineable)
}
func (suite *StatusStatusHomeTimelineableTestSuite) TestFollowingBoostedStatusHomeTimelineableNoReblogs() {
ctx := context.Background()
// Update follow to indicate that local_account_1
// doesn't want to see reblogs by admin_account.
follow := &gtsmodel.Follow{}
*follow = *suite.testFollows["local_account_1_admin_account"]
follow.ShowReblogs = util.Ptr(false)
if err := suite.db.UpdateFollow(ctx, follow, "show_reblogs"); err != nil {
suite.FailNow(err.Error())
}
testStatus := suite.testStatuses["admin_account_status_4"]
testAccount := suite.testAccounts["local_account_1"]
timelineable, err := suite.filter.StatusHomeTimelineable(ctx, testAccount, testStatus)
suite.NoError(err)
suite.False(timelineable)
}
func (suite *StatusStatusHomeTimelineableTestSuite) TestNotFollowingStatusHomeTimelineable() { func (suite *StatusStatusHomeTimelineableTestSuite) TestNotFollowingStatusHomeTimelineable() {
testStatus := suite.testStatuses["remote_account_1_status_1"] testStatus := suite.testStatuses["remote_account_1_status_1"]
testAccount := suite.testAccounts["local_account_1"] testAccount := suite.testAccounts["local_account_1"]