mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 11:12:26 -05:00 
			
		
		
		
	[bugfix] Delete mutual follow (requests) when receiving block from remote (#1960)
* [bugfix] Delete mutual follow (requests) on block * fix test
This commit is contained in:
		
					parent
					
						
							
								747ea584bd
							
						
					
				
			
			
				commit
				
					
						f40bb02f31
					
				
			
		
					 5 changed files with 112 additions and 24 deletions
				
			
		|  | @ -232,6 +232,29 @@ func (r *relationshipDB) deleteFollow(ctx context.Context, id string) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (r *relationshipDB) DeleteFollow(ctx context.Context, sourceAccountID string, targetAccountID string) error { | ||||||
|  | 	defer r.state.Caches.GTS.Follow().Invalidate("AccountID.TargetAccountID", sourceAccountID, targetAccountID) | ||||||
|  | 
 | ||||||
|  | 	// Load follow into cache before attempting a delete, | ||||||
|  | 	// as we need it cached in order to trigger the invalidate | ||||||
|  | 	// callback. This in turn invalidates others. | ||||||
|  | 	follow, err := r.GetFollow( | ||||||
|  | 		gtscontext.SetBarebones(ctx), | ||||||
|  | 		sourceAccountID, | ||||||
|  | 		targetAccountID, | ||||||
|  | 	) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if errors.Is(err, db.ErrNoEntries) { | ||||||
|  | 			// Already gone. | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Finally delete follow from DB. | ||||||
|  | 	return r.deleteFollow(ctx, follow.ID) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (r *relationshipDB) DeleteFollowByID(ctx context.Context, id string) error { | func (r *relationshipDB) DeleteFollowByID(ctx context.Context, id string) error { | ||||||
| 	defer r.state.Caches.GTS.Follow().Invalidate("ID", id) | 	defer r.state.Caches.GTS.Follow().Invalidate("ID", id) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -231,38 +231,44 @@ func (r *relationshipDB) AcceptFollowRequest(ctx context.Context, sourceAccountI | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *relationshipDB) RejectFollowRequest(ctx context.Context, sourceAccountID string, targetAccountID string) db.Error { | func (r *relationshipDB) RejectFollowRequest(ctx context.Context, sourceAccountID string, targetAccountID string) db.Error { | ||||||
|  | 	// Delete follow request first. | ||||||
|  | 	if err := r.DeleteFollowRequest(ctx, sourceAccountID, targetAccountID); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Delete follow request notification | ||||||
|  | 	return r.state.DB.DeleteNotifications(ctx, []string{ | ||||||
|  | 		string(gtsmodel.NotificationFollowRequest), | ||||||
|  | 	}, targetAccountID, sourceAccountID) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (r *relationshipDB) DeleteFollowRequest(ctx context.Context, sourceAccountID string, targetAccountID string) error { | ||||||
| 	defer r.state.Caches.GTS.FollowRequest().Invalidate("AccountID.TargetAccountID", sourceAccountID, targetAccountID) | 	defer r.state.Caches.GTS.FollowRequest().Invalidate("AccountID.TargetAccountID", sourceAccountID, targetAccountID) | ||||||
| 
 | 
 | ||||||
| 	// Load followreq into cache before attempting a delete, | 	// Load followreq into cache before attempting a delete, | ||||||
| 	// as we need it cached in order to trigger the invalidate | 	// as we need it cached in order to trigger the invalidate | ||||||
| 	// callback. This in turn invalidates others. | 	// callback. This in turn invalidates others. | ||||||
| 	_, err := r.GetFollowRequest(gtscontext.SetBarebones(ctx), | 	follow, err := r.GetFollowRequest( | ||||||
|  | 		gtscontext.SetBarebones(ctx), | ||||||
| 		sourceAccountID, | 		sourceAccountID, | ||||||
| 		targetAccountID, | 		targetAccountID, | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | 		if errors.Is(err, db.ErrNoEntries) { | ||||||
|  | 			// Already gone. | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Attempt to delete follow request. | 	// Finally delete followreq from DB. | ||||||
| 	if _, err = r.conn.NewDelete(). | 	_, err = r.conn.NewDelete(). | ||||||
| 		Table("follow_requests"). | 		Table("follow_requests"). | ||||||
| 		Where("? = ? AND ? = ?", | 		Where("? = ?", bun.Ident("id"), follow.ID). | ||||||
| 			bun.Ident("account_id"), | 		Exec(ctx) | ||||||
| 			sourceAccountID, |  | ||||||
| 			bun.Ident("target_account_id"), |  | ||||||
| 			targetAccountID, |  | ||||||
| 		). |  | ||||||
| 		Exec(ctx); err != nil { |  | ||||||
| 	return r.conn.ProcessError(err) | 	return r.conn.ProcessError(err) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 	// Delete original follow request notification |  | ||||||
| 	return r.state.DB.DeleteNotifications(ctx, []string{ |  | ||||||
| 		string(gtsmodel.NotificationFollowRequest), |  | ||||||
| 	}, targetAccountID, sourceAccountID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (r *relationshipDB) DeleteFollowRequestByID(ctx context.Context, id string) error { | func (r *relationshipDB) DeleteFollowRequestByID(ctx context.Context, id string) error { | ||||||
| 	defer r.state.Caches.GTS.FollowRequest().Invalidate("ID", id) | 	defer r.state.Caches.GTS.FollowRequest().Invalidate("ID", id) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -734,7 +734,7 @@ func (suite *RelationshipTestSuite) TestRejectFollowRequestNotExisting() { | ||||||
| 	targetAccount := suite.testAccounts["local_account_2"] | 	targetAccount := suite.testAccounts["local_account_2"] | ||||||
| 
 | 
 | ||||||
| 	err := suite.db.RejectFollowRequest(ctx, account.ID, targetAccount.ID) | 	err := suite.db.RejectFollowRequest(ctx, account.ID, targetAccount.ID) | ||||||
| 	suite.ErrorIs(err, db.ErrNoEntries) | 	suite.NoError(err) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (suite *RelationshipTestSuite) TestGetAccountFollowRequests() { | func (suite *RelationshipTestSuite) TestGetAccountFollowRequests() { | ||||||
|  | @ -836,6 +836,19 @@ func (suite *RelationshipTestSuite) TestGetFollowNotExisting() { | ||||||
| 	suite.Nil(follow) | 	suite.Nil(follow) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (suite *RelationshipTestSuite) TestDeleteFollow() { | ||||||
|  | 	ctx := context.Background() | ||||||
|  | 	originAccount := suite.testAccounts["local_account_1"] | ||||||
|  | 	targetAccount := suite.testAccounts["admin_account"] | ||||||
|  | 
 | ||||||
|  | 	err := suite.db.DeleteFollow(ctx, originAccount.ID, targetAccount.ID) | ||||||
|  | 	suite.NoError(err) | ||||||
|  | 
 | ||||||
|  | 	follow, err := suite.db.GetFollow(ctx, originAccount.ID, targetAccount.ID) | ||||||
|  | 	suite.EqualError(err, db.ErrNoEntries.Error()) | ||||||
|  | 	suite.Nil(follow) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (suite *RelationshipTestSuite) TestUnfollowRequestExisting() { | func (suite *RelationshipTestSuite) TestUnfollowRequestExisting() { | ||||||
| 	ctx := context.Background() | 	ctx := context.Background() | ||||||
| 	originAccount := suite.testAccounts["admin_account"] | 	originAccount := suite.testAccounts["admin_account"] | ||||||
|  |  | ||||||
|  | @ -97,12 +97,18 @@ type Relationship interface { | ||||||
| 	// UpdateFollowRequest updates one follow request by ID. | 	// UpdateFollowRequest updates one follow request by ID. | ||||||
| 	UpdateFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest, columns ...string) error | 	UpdateFollowRequest(ctx context.Context, followRequest *gtsmodel.FollowRequest, columns ...string) error | ||||||
| 
 | 
 | ||||||
|  | 	// DeleteFollow deletes a follow if it exists between source and target accounts. | ||||||
|  | 	DeleteFollow(ctx context.Context, sourceAccountID string, targetAccountID string) error | ||||||
|  | 
 | ||||||
| 	// DeleteFollowByID deletes a follow from the database with the given ID. | 	// DeleteFollowByID deletes a follow from the database with the given ID. | ||||||
| 	DeleteFollowByID(ctx context.Context, id string) error | 	DeleteFollowByID(ctx context.Context, id string) error | ||||||
| 
 | 
 | ||||||
| 	// DeleteFollowByURI deletes a follow from the database with the given URI. | 	// DeleteFollowByURI deletes a follow from the database with the given URI. | ||||||
| 	DeleteFollowByURI(ctx context.Context, uri string) error | 	DeleteFollowByURI(ctx context.Context, uri string) error | ||||||
| 
 | 
 | ||||||
|  | 	// DeleteFollowRequest deletes a follow request if it exists between source and target accounts. | ||||||
|  | 	DeleteFollowRequest(ctx context.Context, sourceAccountID string, targetAccountID string) error | ||||||
|  | 
 | ||||||
| 	// DeleteFollowRequestByID deletes a follow request from the database with the given ID. | 	// DeleteFollowRequestByID deletes a follow request from the database with the given ID. | ||||||
| 	DeleteFollowRequestByID(ctx context.Context, id string) error | 	DeleteFollowRequestByID(ctx context.Context, id string) error | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -352,18 +352,58 @@ func (p *Processor) processCreateAnnounceFromFederator(ctx context.Context, fede | ||||||
| func (p *Processor) processCreateBlockFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | func (p *Processor) processCreateBlockFromFederator(ctx context.Context, federatorMsg messages.FromFederator) error { | ||||||
| 	block, ok := federatorMsg.GTSModel.(*gtsmodel.Block) | 	block, ok := federatorMsg.GTSModel.(*gtsmodel.Block) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return errors.New("block was not parseable as *gtsmodel.Block") | 		return gtserror.New("block was not parseable as *gtsmodel.Block") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// remove any of the blocking account's statuses from the blocked account's timeline, and vice versa | 	// Remove each account's posts from the other's timelines. | ||||||
|  | 	// | ||||||
|  | 	// First home timelines. | ||||||
| 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { | 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { | ||||||
| 		return err | 		return gtserror.Newf("%w", err) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { | 	if err := p.state.Timelines.Home.WipeItemsFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { | ||||||
| 		return err | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Now list timelines. | ||||||
|  | 	if err := p.state.Timelines.List.WipeItemsFromAccountID(ctx, block.AccountID, block.TargetAccountID); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := p.state.Timelines.List.WipeItemsFromAccountID(ctx, block.TargetAccountID, block.AccountID); err != nil { | ||||||
|  | 		return gtserror.Newf("%w", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Remove any follows that existed between blocker + blockee. | ||||||
|  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.AccountID, block.TargetAccountID); err != nil { | ||||||
|  | 		return gtserror.Newf( | ||||||
|  | 			"db error deleting follow from %s targeting %s: %w", | ||||||
|  | 			block.AccountID, block.TargetAccountID, err, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.TargetAccountID, block.AccountID); err != nil { | ||||||
|  | 		return gtserror.Newf( | ||||||
|  | 			"db error deleting follow from %s targeting %s: %w", | ||||||
|  | 			block.TargetAccountID, block.AccountID, err, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Remove any follow requests that existed between blocker + blockee. | ||||||
|  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.AccountID, block.TargetAccountID); err != nil { | ||||||
|  | 		return gtserror.Newf( | ||||||
|  | 			"db error deleting follow request from %s targeting %s: %w", | ||||||
|  | 			block.AccountID, block.TargetAccountID, err, | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := p.state.DB.DeleteFollowRequest(ctx, block.TargetAccountID, block.AccountID); err != nil { | ||||||
|  | 		return gtserror.Newf( | ||||||
|  | 			"db error deleting follow request from %s targeting %s: %w", | ||||||
|  | 			block.TargetAccountID, block.AccountID, err, | ||||||
|  | 		) | ||||||
| 	} | 	} | ||||||
| 	// TODO: same with notifications |  | ||||||
| 	// TODO: same with bookmarks |  | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue