mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 19:02:26 -06:00 
			
		
		
		
	federate status deletes properly
This commit is contained in:
		
					parent
					
						
							
								5d2b69c256
							
						
					
				
			
			
				commit
				
					
						197ef03ead
					
				
			
		
					 19 changed files with 154 additions and 143 deletions
				
			
		| 
						 | 
					@ -56,5 +56,11 @@ func (m *Module) StatusDELETEHandler(c *gin.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// the status was already gone/never existed
 | 
				
			||||||
 | 
						if mastoStatus == nil {
 | 
				
			||||||
 | 
							c.JSON(http.StatusNotFound, gin.H{"error": "Record not found"})
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.JSON(http.StatusOK, mastoStatus)
 | 
						c.JSON(http.StatusOK, mastoStatus)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,7 +212,7 @@ type DB interface {
 | 
				
			||||||
	// 3. Accounts boosted by the target status
 | 
						// 3. Accounts boosted by the target status
 | 
				
			||||||
	//
 | 
						//
 | 
				
			||||||
	// Will return an error if something goes wrong while pulling stuff out of the database.
 | 
						// Will return an error if something goes wrong while pulling stuff out of the database.
 | 
				
			||||||
	StatusVisible(targetStatus *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error)
 | 
						StatusVisible(targetStatus *gtsmodel.Status, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Follows returns true if sourceAccount follows target account, or an error if something goes wrong while finding out.
 | 
						// Follows returns true if sourceAccount follows target account, or an error if something goes wrong while finding out.
 | 
				
			||||||
	Follows(sourceAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) (bool, error)
 | 
						Follows(sourceAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) (bool, error)
 | 
				
			||||||
| 
						 | 
					@ -247,10 +247,6 @@ type DB interface {
 | 
				
			||||||
	// StatusBookmarkedBy checks if a given status has been bookmarked by a given account ID
 | 
						// StatusBookmarkedBy checks if a given status has been bookmarked by a given account ID
 | 
				
			||||||
	StatusBookmarkedBy(status *gtsmodel.Status, accountID string) (bool, error)
 | 
						StatusBookmarkedBy(status *gtsmodel.Status, accountID string) (bool, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// UnfaveStatus unfaves the given status, using accountID as the unfaver (sure, that's a word).
 | 
					 | 
				
			||||||
	// The returned fave will be nil if the status was already not faved.
 | 
					 | 
				
			||||||
	UnfaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// WhoFavedStatus returns a slice of accounts who faved the given status.
 | 
						// WhoFavedStatus returns a slice of accounts who faved the given status.
 | 
				
			||||||
	// This slice will be unfiltered, not taking account of blocks and whatnot, so filter it before serving it back to a user.
 | 
						// This slice will be unfiltered, not taking account of blocks and whatnot, so filter it before serving it back to a user.
 | 
				
			||||||
	WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error)
 | 
						WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error)
 | 
				
			||||||
| 
						 | 
					@ -261,10 +257,6 @@ type DB interface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	GetStatusesWhereFollowing(accountID string, limit int, offsetStatusID string) ([]*gtsmodel.Status, error)
 | 
						GetStatusesWhereFollowing(accountID string, limit int, offsetStatusID string) ([]*gtsmodel.Status, error)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// GetHomeTimelineForAccount fetches the account's HOME timeline -- ie., posts and replies from people they *follow*.
 | 
					 | 
				
			||||||
	// It will use the given filters and try to return as many statuses up to the limit as possible.
 | 
					 | 
				
			||||||
	GetHomeTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// GetPublicTimelineForAccount fetches the account's PUBLIC timline -- ie., posts and replies that are public.
 | 
						// GetPublicTimelineForAccount fetches the account's PUBLIC timline -- ie., posts and replies that are public.
 | 
				
			||||||
	// It will use the given filters and try to return as many statuses as possible up to the limit.
 | 
						// It will use the given filters and try to return as many statuses as possible up to the limit.
 | 
				
			||||||
	GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error)
 | 
						GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -785,9 +785,11 @@ func (ps *postgresService) GetRelationship(requestingAccount string, targetAccou
 | 
				
			||||||
	return r, nil
 | 
						return r, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error) {
 | 
					func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, requestingAccount *gtsmodel.Account, relevantAccounts *gtsmodel.RelevantAccounts) (bool, error) {
 | 
				
			||||||
	l := ps.log.WithField("func", "StatusVisible")
 | 
						l := ps.log.WithField("func", "StatusVisible")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						targetAccount := relevantAccounts.StatusAuthor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// if target account is suspended then don't show the status
 | 
						// if target account is suspended then don't show the status
 | 
				
			||||||
	if !targetAccount.SuspendedAt.IsZero() {
 | 
						if !targetAccount.SuspendedAt.IsZero() {
 | 
				
			||||||
		l.Debug("target account suspended at is not zero")
 | 
							l.Debug("target account suspended at is not zero")
 | 
				
			||||||
| 
						 | 
					@ -869,7 +871,7 @@ func (ps *postgresService) StatusVisible(targetStatus *gtsmodel.Status, targetAc
 | 
				
			||||||
	// check other accounts mentioned/boosted by/replied to by the status, if they exist
 | 
						// check other accounts mentioned/boosted by/replied to by the status, if they exist
 | 
				
			||||||
	if relevantAccounts != nil {
 | 
						if relevantAccounts != nil {
 | 
				
			||||||
		// status replies to account id
 | 
							// status replies to account id
 | 
				
			||||||
		if relevantAccounts.ReplyToAccount != nil {
 | 
							if relevantAccounts.ReplyToAccount != nil && relevantAccounts.ReplyToAccount.ID != requestingAccount.ID {
 | 
				
			||||||
			if blocked, err := ps.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID); err != nil {
 | 
								if blocked, err := ps.Blocked(relevantAccounts.ReplyToAccount.ID, requestingAccount.ID); err != nil {
 | 
				
			||||||
				return false, err
 | 
									return false, err
 | 
				
			||||||
			} else if blocked {
 | 
								} else if blocked {
 | 
				
			||||||
| 
						 | 
					@ -1087,55 +1089,6 @@ func (ps *postgresService) StatusBookmarkedBy(status *gtsmodel.Status, accountID
 | 
				
			||||||
	return ps.conn.Model(>smodel.StatusBookmark{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Exists()
 | 
						return ps.conn.Model(>smodel.StatusBookmark{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Exists()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// func (ps *postgresService) FaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) {
 | 
					 | 
				
			||||||
// 	// first check if a fave already exists, we can just return if so
 | 
					 | 
				
			||||||
// 	existingFave := >smodel.StatusFave{}
 | 
					 | 
				
			||||||
// 	err := ps.conn.Model(existingFave).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Select()
 | 
					 | 
				
			||||||
// 	if err == nil {
 | 
					 | 
				
			||||||
// 		// fave already exists so just return nothing at all
 | 
					 | 
				
			||||||
// 		return nil, nil
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 	// an error occurred so it might exist or not, we don't know
 | 
					 | 
				
			||||||
// 	if err != pg.ErrNoRows {
 | 
					 | 
				
			||||||
// 		return nil, err
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 	// it doesn't exist so create it
 | 
					 | 
				
			||||||
// 	newFave := >smodel.StatusFave{
 | 
					 | 
				
			||||||
// 		AccountID:       accountID,
 | 
					 | 
				
			||||||
// 		TargetAccountID: status.AccountID,
 | 
					 | 
				
			||||||
// 		StatusID:        status.ID,
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
// 	if _, err = ps.conn.Model(newFave).Insert(); err != nil {
 | 
					 | 
				
			||||||
// 		return nil, err
 | 
					 | 
				
			||||||
// 	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 	return newFave, nil
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ps *postgresService) UnfaveStatus(status *gtsmodel.Status, accountID string) (*gtsmodel.StatusFave, error) {
 | 
					 | 
				
			||||||
	// if a fave doesn't exist, we don't need to do anything
 | 
					 | 
				
			||||||
	existingFave := >smodel.StatusFave{}
 | 
					 | 
				
			||||||
	err := ps.conn.Model(existingFave).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Select()
 | 
					 | 
				
			||||||
	// the fave doesn't exist so return nothing at all
 | 
					 | 
				
			||||||
	if err == pg.ErrNoRows {
 | 
					 | 
				
			||||||
		return nil, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// an error occurred so it might exist or not, we don't know
 | 
					 | 
				
			||||||
	if err != nil && err != pg.ErrNoRows {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// the fave exists so remove it
 | 
					 | 
				
			||||||
	if _, err = ps.conn.Model(>smodel.StatusFave{}).Where("status_id = ?", status.ID).Where("account_id = ?", accountID).Delete(); err != nil {
 | 
					 | 
				
			||||||
		return nil, err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return existingFave, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ps *postgresService) WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error) {
 | 
					func (ps *postgresService) WhoFavedStatus(status *gtsmodel.Status) ([]*gtsmodel.Account, error) {
 | 
				
			||||||
	accounts := []*gtsmodel.Account{}
 | 
						accounts := []*gtsmodel.Account{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1216,56 +1169,13 @@ func (ps *postgresService) GetStatusesWhereFollowing(accountID string, limit int
 | 
				
			||||||
	return statuses, nil
 | 
						return statuses, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ps *postgresService) GetHomeTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error) {
 | 
					 | 
				
			||||||
	statuses := []*gtsmodel.Status{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	q := ps.conn.Model(&statuses)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	q = q.ColumnExpr("status.*").
 | 
					 | 
				
			||||||
		Join("JOIN follows AS f ON f.target_account_id = status.account_id").
 | 
					 | 
				
			||||||
		Where("f.account_id = ?", accountID).
 | 
					 | 
				
			||||||
		Limit(limit).
 | 
					 | 
				
			||||||
		Order("status.created_at DESC")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if maxID != "" {
 | 
					 | 
				
			||||||
		s := >smodel.Status{}
 | 
					 | 
				
			||||||
		if err := ps.conn.Model(s).Where("id = ?", maxID).Select(); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		q = q.Where("status.created_at < ?", s.CreatedAt)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if minID != "" {
 | 
					 | 
				
			||||||
		s := >smodel.Status{}
 | 
					 | 
				
			||||||
		if err := ps.conn.Model(s).Where("id = ?", minID).Select(); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		q = q.Where("status.created_at > ?", s.CreatedAt)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if sinceID != "" {
 | 
					 | 
				
			||||||
		s := >smodel.Status{}
 | 
					 | 
				
			||||||
		if err := ps.conn.Model(s).Where("id = ?", sinceID).Select(); err != nil {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		q = q.Where("status.created_at > ?", s.CreatedAt)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err := q.Select()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if err != pg.ErrNoRows {
 | 
					 | 
				
			||||||
			return nil, err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return statuses, nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ps *postgresService) GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error) {
 | 
					func (ps *postgresService) GetPublicTimelineForAccount(accountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]*gtsmodel.Status, error) {
 | 
				
			||||||
	statuses := []*gtsmodel.Status{}
 | 
						statuses := []*gtsmodel.Status{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	q := ps.conn.Model(&statuses).
 | 
						q := ps.conn.Model(&statuses).
 | 
				
			||||||
		Where("visibility = ?", gtsmodel.VisibilityPublic).
 | 
							Where("visibility = ?", gtsmodel.VisibilityPublic).
 | 
				
			||||||
 | 
							Where("? IS NULL", pg.Ident("in_reply_to_id")).
 | 
				
			||||||
 | 
							Where("? IS NULL", pg.Ident("boost_of_id")).
 | 
				
			||||||
		Limit(limit).
 | 
							Limit(limit).
 | 
				
			||||||
		Order("created_at DESC")
 | 
							Order("created_at DESC")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,7 +227,7 @@ func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID strin
 | 
				
			||||||
			return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant statuses: %s", err))
 | 
								return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant statuses: %s", err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		visible, err := p.db.StatusVisible(&s, targetAccount, authed.Account, relevantAccounts)
 | 
							visible, err := p.db.StatusVisible(&s, authed.Account, relevantAccounts)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking status visibility: %s", err))
 | 
								return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking status visibility: %s", err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -246,7 +246,7 @@ func (p *processor) AccountStatusesGet(authed *oauth.Auth, targetAccountID strin
 | 
				
			||||||
				return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant accounts from boosted status: %s", err))
 | 
									return nil, gtserror.NewErrorInternalError(fmt.Errorf("error getting relevant accounts from boosted status: %s", err))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			boostedVisible, err := p.db.StatusVisible(bs, relevantAccounts.BoostedAccount, authed.Account, boostedRelevantAccounts)
 | 
								boostedVisible, err := p.db.StatusVisible(bs, authed.Account, boostedRelevantAccounts)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking boosted status visibility: %s", err))
 | 
									return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking boosted status visibility: %s", err))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,6 +135,22 @@ func (p *processor) processFromClientAPI(clientMsg gtsmodel.FromClientAPI) error
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return p.federateUnfave(fave, clientMsg.OriginAccount, clientMsg.TargetAccount)
 | 
								return p.federateUnfave(fave, clientMsg.OriginAccount, clientMsg.TargetAccount)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						case gtsmodel.ActivityStreamsDelete:
 | 
				
			||||||
 | 
							// DELETE
 | 
				
			||||||
 | 
							switch clientMsg.APObjectType {
 | 
				
			||||||
 | 
							case gtsmodel.ActivityStreamsNote:
 | 
				
			||||||
 | 
								// DELETE STATUS/NOTE
 | 
				
			||||||
 | 
								statusToDelete, ok := clientMsg.GTSModel.(*gtsmodel.Status)
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									return errors.New("note was not parseable as *gtsmodel.Status")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if err := p.deleteStatusFromTimelines(statusToDelete); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return p.federateStatusDelete(statusToDelete, clientMsg.OriginAccount)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -154,6 +170,43 @@ func (p *processor) federateStatus(status *gtsmodel.Status) error {
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *processor) federateStatusDelete(status *gtsmodel.Status, originAccount *gtsmodel.Account) error {
 | 
				
			||||||
 | 
						asStatus, err := p.tc.StatusToAS(status)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("federateStatusDelete: error converting status to as format: %s", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						outboxIRI, err := url.Parse(originAccount.OutboxURI)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("federateStatusDelete: error parsing outboxURI %s: %s", originAccount.OutboxURI, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						actorIRI, err := url.Parse(originAccount.URI)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("federateStatusDelete: error parsing actorIRI %s: %s", originAccount.URI, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create a delete and set the appropriate actor on it
 | 
				
			||||||
 | 
						delete := streams.NewActivityStreamsDelete()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// set the actor for the delete
 | 
				
			||||||
 | 
						deleteActor := streams.NewActivityStreamsActorProperty()
 | 
				
			||||||
 | 
						deleteActor.AppendIRI(actorIRI)
 | 
				
			||||||
 | 
						delete.SetActivityStreamsActor(deleteActor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Set the status as the 'object' property.
 | 
				
			||||||
 | 
						deleteObject := streams.NewActivityStreamsObjectProperty()
 | 
				
			||||||
 | 
						deleteObject.AppendActivityStreamsNote(asStatus)
 | 
				
			||||||
 | 
						delete.SetActivityStreamsObject(deleteObject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// set the to and cc as the original to/cc of the original status
 | 
				
			||||||
 | 
						delete.SetActivityStreamsTo(asStatus.GetActivityStreamsTo())
 | 
				
			||||||
 | 
						delete.SetActivityStreamsCc(asStatus.GetActivityStreamsCc())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = p.federator.FederatingActor().Send(context.Background(), outboxIRI, delete)
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
 | 
					func (p *processor) federateFollow(followRequest *gtsmodel.FollowRequest, originAccount *gtsmodel.Account, targetAccount *gtsmodel.Account) error {
 | 
				
			||||||
	// if both accounts are local there's nothing to do here
 | 
						// if both accounts are local there's nothing to do here
 | 
				
			||||||
	if originAccount.Domain == "" && targetAccount.Domain == "" {
 | 
						if originAccount.Domain == "" && targetAccount.Domain == "" {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,7 +286,7 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// make sure the status is visible
 | 
						// make sure the status is visible
 | 
				
			||||||
	visible, err := p.db.StatusVisible(status, status.GTSAuthorAccount, timelineAccount, relevantAccounts)
 | 
						visible, err := p.db.StatusVisible(status, timelineAccount, relevantAccounts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		errors <- fmt.Errorf("timelineStatus: error getting visibility for status for timeline with id %s: %s", accountID, err)
 | 
							errors <- fmt.Errorf("timelineStatus: error getting visibility for status for timeline with id %s: %s", accountID, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -301,6 +301,6 @@ func (p *processor) timelineStatusForAccount(status *gtsmodel.Status, accountID
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *processor) fullyDeleteStatus(status *gtsmodel.Status, accountID string) error {
 | 
					func (p *processor) deleteStatusFromTimelines(status *gtsmodel.Status) error {
 | 
				
			||||||
	return nil
 | 
						return p.timelineManager.WipeStatusFromAllTimelines(status.ID)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,6 +146,11 @@ func (p *processor) processFromFederator(federatorMsg gtsmodel.FromFederator) er
 | 
				
			||||||
			// 1. delete all media associated with status
 | 
								// 1. delete all media associated with status
 | 
				
			||||||
			// 2. delete boosts of status
 | 
								// 2. delete boosts of status
 | 
				
			||||||
			// 3. etc etc etc
 | 
								// 3. etc etc etc
 | 
				
			||||||
 | 
								statusToDelete, ok := federatorMsg.GTSModel.(*gtsmodel.Status)
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									return errors.New("note was not parseable as *gtsmodel.Status")
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return p.deleteStatusFromTimelines(statusToDelete)
 | 
				
			||||||
		case gtsmodel.ActivityStreamsProfile:
 | 
							case gtsmodel.ActivityStreamsProfile:
 | 
				
			||||||
			// DELETE A PROFILE/ACCOUNT
 | 
								// DELETE A PROFILE/ACCOUNT
 | 
				
			||||||
			// TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account
 | 
								// TODO: handle side effects of account deletion here: delete all objects, statuses, media etc associated with account
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -109,7 +109,7 @@ func (p *processor) SearchGet(authed *oauth.Auth, searchQuery *apimodel.SearchQu
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if visible, err := p.db.StatusVisible(foundStatus, statusOwner, authed.Account, relevantAccounts); !visible || err != nil {
 | 
							if visible, err := p.db.StatusVisible(foundStatus, authed.Account, relevantAccounts); !visible || err != nil {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func (p *processor) Boost(account *gtsmodel.Account, application *gtsmodel.Appli
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func (p *processor) BoostedBy(account *gtsmodel.Account, targetStatusID string)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("StatusBoostedBy: error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
 | 
						apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
 | 
				
			||||||
 | 
						"github.com/superseriousbusiness/gotosocial/internal/db"
 | 
				
			||||||
	"github.com/superseriousbusiness/gotosocial/internal/gtserror"
 | 
						"github.com/superseriousbusiness/gotosocial/internal/gtserror"
 | 
				
			||||||
	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
 | 
						"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -14,8 +15,12 @@ func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*a
 | 
				
			||||||
	l.Tracef("going to search for target status %s", targetStatusID)
 | 
						l.Tracef("going to search for target status %s", targetStatusID)
 | 
				
			||||||
	targetStatus := >smodel.Status{}
 | 
						targetStatus := >smodel.Status{}
 | 
				
			||||||
	if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
 | 
						if err := p.db.GetByID(targetStatusID, targetStatus); err != nil {
 | 
				
			||||||
 | 
							if _, ok := err.(db.ErrNoEntries); !ok {
 | 
				
			||||||
			return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
 | 
								return nil, gtserror.NewErrorNotFound(fmt.Errorf("error fetching status %s: %s", targetStatusID, err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							// status is already gone
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if targetStatus.AccountID != account.ID {
 | 
						if targetStatus.AccountID != account.ID {
 | 
				
			||||||
		return nil, gtserror.NewErrorForbidden(errors.New("status doesn't belong to requesting account"))
 | 
							return nil, gtserror.NewErrorForbidden(errors.New("status doesn't belong to requesting account"))
 | 
				
			||||||
| 
						 | 
					@ -40,7 +45,7 @@ func (p *processor) Delete(account *gtsmodel.Account, targetStatusID string) (*a
 | 
				
			||||||
		return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorInternalError(fmt.Errorf("error converting status %s to frontend representation: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := p.db.DeleteByID(targetStatus.ID, targetStatus); err != nil {
 | 
						if err := p.db.DeleteByID(targetStatus.ID, >smodel.Status{}); err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorInternalError(fmt.Errorf("error deleting status from the database: %s", err))
 | 
							return nil, gtserror.NewErrorInternalError(fmt.Errorf("error deleting status from the database: %s", err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ func (p *processor) Fave(account *gtsmodel.Account, targetStatusID string) (*api
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func (p *processor) FavedBy(account *gtsmodel.Account, targetStatusID string) ([
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func (p *processor) Get(account *gtsmodel.Account, targetStatusID string) (*apim
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	l.Trace("going to see if status is visible")
 | 
						l.Trace("going to see if status is visible")
 | 
				
			||||||
	visible, err := p.db.StatusVisible(targetStatus, targetAccount, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
						visible, err := p.db.StatusVisible(targetStatus, account, relevantAccounts) // requestingAccount might well be nil here, but StatusVisible knows how to take care of that
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
							return nil, gtserror.NewErrorNotFound(fmt.Errorf("error seeing if status %s is visible: %s", targetStatus.ID, err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -60,8 +60,7 @@ func (p *processor) Unfave(account *gtsmodel.Account, targetStatusID string) (*a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if toUnfave {
 | 
						if toUnfave {
 | 
				
			||||||
		// we had a fave, so take some action to get rid of it
 | 
							// we had a fave, so take some action to get rid of it
 | 
				
			||||||
		_, err = p.db.UnfaveStatus(targetStatus, account.ID)
 | 
							if err := p.db.DeleteWhere([]db.Where{{Key: "status_id", Value: targetStatus.ID}, {Key: "account_id", Value: account.ID}}, gtsFave); err != nil {
 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unfaveing status: %s", err))
 | 
								return nil, gtserror.NewErrorInternalError(fmt.Errorf("error unfaveing status: %s", err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,7 +74,7 @@ func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Stat
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		visible, err := p.db.StatusVisible(s, targetAccount, authed.Account, relevantAccounts)
 | 
							visible, err := p.db.StatusVisible(s, authed.Account, relevantAccounts)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking status visibility: %s", err))
 | 
								return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking status visibility: %s", err))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -98,7 +98,7 @@ func (p *processor) filterStatuses(authed *oauth.Auth, statuses []*gtsmodel.Stat
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			boostedVisible, err := p.db.StatusVisible(bs, relevantAccounts.BoostedAccount, authed.Account, boostedRelevantAccounts)
 | 
								boostedVisible, err := p.db.StatusVisible(bs, authed.Account, boostedRelevantAccounts)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking boosted status visibility: %s", err))
 | 
									return nil, gtserror.NewErrorInternalError(fmt.Errorf("HomeTimelineGet: error checking boosted status visibility: %s", err))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -204,7 +204,7 @@ func (p *processor) indexAndIngest(statuses []*gtsmodel.Status, timelineAccount
 | 
				
			||||||
			l.Error(fmt.Errorf("initTimelineFor: error getting relevant accounts from status %s: %s", s.ID, err))
 | 
								l.Error(fmt.Errorf("initTimelineFor: error getting relevant accounts from status %s: %s", s.ID, err))
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		visible, err := p.db.StatusVisible(s, relevantAccounts.StatusAuthor, timelineAccount, relevantAccounts)
 | 
							visible, err := p.db.StatusVisible(s, timelineAccount, relevantAccounts)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			l.Error(fmt.Errorf("initTimelineFor: error checking visibility of status %s: %s", s.ID, err))
 | 
								l.Error(fmt.Errorf("initTimelineFor: error checking visibility of status %s: %s", s.ID, err))
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,8 @@
 | 
				
			||||||
package timeline
 | 
					package timeline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/sirupsen/logrus"
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
| 
						 | 
					@ -66,6 +68,10 @@ type Manager interface {
 | 
				
			||||||
	GetOldestIndexedID(timelineAccountID string) (string, error)
 | 
						GetOldestIndexedID(timelineAccountID string) (string, error)
 | 
				
			||||||
	// PrepareXFromTop prepares limit n amount of posts, based on their indexed representations, from the top of the index.
 | 
						// PrepareXFromTop prepares limit n amount of posts, based on their indexed representations, from the top of the index.
 | 
				
			||||||
	PrepareXFromTop(timelineAccountID string, limit int) error
 | 
						PrepareXFromTop(timelineAccountID string, limit int) error
 | 
				
			||||||
 | 
						// WipeStatusFromTimeline completely removes a status and from the index and prepared posts of the given account ID
 | 
				
			||||||
 | 
						WipeStatusFromTimeline(timelineAccountID string, statusID string) error
 | 
				
			||||||
 | 
						// WipeStatusFromAllTimelines removes the status from the index and prepared posts of all timelines
 | 
				
			||||||
 | 
						WipeStatusFromAllTimelines(statusID string) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewManager returns a new timeline manager with the given database, typeconverter, config, and log.
 | 
					// NewManager returns a new timeline manager with the given database, typeconverter, config, and log.
 | 
				
			||||||
| 
						 | 
					@ -172,6 +178,37 @@ func (m *manager) PrepareXFromTop(timelineAccountID string, limit int) error {
 | 
				
			||||||
	return t.PrepareXFromTop(limit)
 | 
						return t.PrepareXFromTop(limit)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *manager) WipeStatusFromTimeline(timelineAccountID string, statusID string) error {
 | 
				
			||||||
 | 
						t := m.getOrCreateTimeline(timelineAccountID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return t.Remove(statusID)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (m *manager) WipeStatusFromAllTimelines(statusID string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						errors := []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.accountTimelines.Range(func(k interface{}, i interface{}) bool {
 | 
				
			||||||
 | 
							t, ok := i.(Timeline)
 | 
				
			||||||
 | 
							if !ok {
 | 
				
			||||||
 | 
								panic("couldn't parse entry as Timeline, this should never happen so panic")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := t.Remove(statusID); err != nil {
 | 
				
			||||||
 | 
								errors = append(errors, err.Error())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						if len(errors) > 0 {
 | 
				
			||||||
 | 
							err = fmt.Errorf("one or more errors removing status %s from all timelines: %s", statusID, strings.Join(errors, ";"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (m *manager) getOrCreateTimeline(timelineAccountID string) Timeline {
 | 
					func (m *manager) getOrCreateTimeline(timelineAccountID string) Timeline {
 | 
				
			||||||
	var t Timeline
 | 
						var t Timeline
 | 
				
			||||||
	i, ok := m.accountTimelines.Load(timelineAccountID)
 | 
						i, ok := m.accountTimelines.Load(timelineAccountID)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -334,6 +334,7 @@ func (t *timeline) Remove(statusID string) error {
 | 
				
			||||||
	t.Lock()
 | 
						t.Lock()
 | 
				
			||||||
	defer t.Unlock()
 | 
						defer t.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if t.postIndex != nil && t.postIndex.data != nil {
 | 
				
			||||||
		// remove the entry from the post index
 | 
							// remove the entry from the post index
 | 
				
			||||||
		for e := t.postIndex.data.Front(); e != nil; e = e.Next() {
 | 
							for e := t.postIndex.data.Front(); e != nil; e = e.Next() {
 | 
				
			||||||
			entry, ok := e.Value.(*postIndexEntry)
 | 
								entry, ok := e.Value.(*postIndexEntry)
 | 
				
			||||||
| 
						 | 
					@ -345,8 +346,10 @@ func (t *timeline) Remove(statusID string) error {
 | 
				
			||||||
				break // bail once we found and removed it
 | 
									break // bail once we found and removed it
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// remove the entry from prepared posts
 | 
						// remove the entry from prepared posts
 | 
				
			||||||
 | 
						if t.preparedPosts != nil && t.preparedPosts.data != nil {
 | 
				
			||||||
		for e := t.preparedPosts.data.Front(); e != nil; e = e.Next() {
 | 
							for e := t.preparedPosts.data.Front(); e != nil; e = e.Next() {
 | 
				
			||||||
			entry, ok := e.Value.(*preparedPostsEntry)
 | 
								entry, ok := e.Value.(*preparedPostsEntry)
 | 
				
			||||||
			if !ok {
 | 
								if !ok {
 | 
				
			||||||
| 
						 | 
					@ -357,6 +360,7 @@ func (t *timeline) Remove(statusID string) error {
 | 
				
			||||||
				break // bail once we found and removed it
 | 
									break // bail once we found and removed it
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -222,7 +222,7 @@ func (c *converter) ASStatusToStatus(statusable Statusable) (*gtsmodel.Status, e
 | 
				
			||||||
	status.APStatusOwnerURI = attributedTo.String()
 | 
						status.APStatusOwnerURI = attributedTo.String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	statusOwner := >smodel.Account{}
 | 
						statusOwner := >smodel.Account{}
 | 
				
			||||||
	if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: attributedTo.String()}}, statusOwner); err != nil {
 | 
						if err := c.db.GetWhere([]db.Where{{Key: "uri", Value: attributedTo.String(), CaseInsensitive: true}}, statusOwner); err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("couldn't get status owner from db: %s", err)
 | 
							return nil, fmt.Errorf("couldn't get status owner from db: %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status.AccountID = statusOwner.ID
 | 
						status.AccountID = statusOwner.ID
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue