diff options
author | 2023-03-20 19:10:08 +0100 | |
---|---|---|
committer | 2023-03-20 18:10:08 +0000 | |
commit | e8595f0c64f527af0913d1a426b697e67ff74ac9 (patch) | |
tree | a5d45b1ad8b96318944408a23fda91f008643900 /internal/processing/fromcommon.go | |
parent | [chore]: Bump github.com/miekg/dns from 1.1.51 to 1.1.52 (#1636) (diff) | |
download | gotosocial-e8595f0c64f527af0913d1a426b697e67ff74ac9.tar.xz |
[chore] Refactor account deleting/block logic, tidy up some other processing things (#1599)
* start refactoring account deletion
* update to use state.DB
* further messing about
* some more tidying up
* more tidying, cleaning, nice-making
* further adventures in refactoring and the woes of technical debt
* update fr accept/reject
* poking + prodding
* fix up deleting
* create fave uri
* don't log using requestingAccount.ID because it might be nil
* move getBookmarks function
* use exists query to check for status bookmark
* use deletenotifications func
* fiddle
* delete follow request notif
* split up some db functions
* Fix possible nil pointer panic
* fix more possible nil pointers
* fix license headers
* warn when follow missing (target) account
* return wrapped err when bookmark/fave models can't be retrieved
* simplify self account delete
* warn log likely race condition
* de-sillify status delete loop
* move error check due north
* warn when unfollowSideEffects has no target account
* warn when no boost account is found
* warn + dump follow when no account
* more warnings
* warn on fave account not set
* move for loop inside anonymous function
* fix funky logic
* don't remove mutual account items on block;
do make sure unfollow occurs in both directions!
Diffstat (limited to 'internal/processing/fromcommon.go')
-rw-r--r-- | internal/processing/fromcommon.go | 103 |
1 files changed, 42 insertions, 61 deletions
diff --git a/internal/processing/fromcommon.go b/internal/processing/fromcommon.go index c29ada5ba..49a05da5d 100644 --- a/internal/processing/fromcommon.go +++ b/internal/processing/fromcommon.go @@ -21,12 +21,11 @@ import ( "context" "errors" "fmt" - "strings" - "sync" "github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/email" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" "github.com/superseriousbusiness/gotosocial/internal/id" "github.com/superseriousbusiness/gotosocial/internal/stream" @@ -413,45 +412,30 @@ func (p *Processor) timelineStatus(ctx context.Context, status *gtsmodel.Status) status.Account = a } - // get local followers of the account that posted the status - follows, err := p.state.DB.GetAccountFollowedBy(ctx, status.AccountID, true) + // Get LOCAL followers of the account that posted the status; + // we know that remote accounts don't have timelines on this + // instance, so there's no point selecting them too. + accountIDs, err := p.state.DB.GetLocalFollowersIDs(ctx, status.AccountID) if err != nil { return fmt.Errorf("timelineStatus: error getting followers for account id %s: %s", status.AccountID, err) } - // if the poster is local, add a fake entry for them to the followers list so they can see their own status in their timeline - if status.Account.Domain == "" { - follows = append(follows, >smodel.Follow{ - AccountID: status.AccountID, - Account: status.Account, - }) + // If the poster is also local, add a fake entry for them + // so they can see their own status in their timeline. + if status.Account.IsLocal() { + accountIDs = append(accountIDs, status.AccountID) } - wg := sync.WaitGroup{} - wg.Add(len(follows)) - errors := make(chan error, len(follows)) - - for _, f := range follows { - go p.timelineStatusForAccount(ctx, status, f.AccountID, errors, &wg) - } - - // read any errors that come in from the async functions - errs := []string{} - go func(errs []string) { - for range errors { - if e := <-errors; e != nil { - errs = append(errs, e.Error()) - } + // Timeline the status for each local following account. + errors := gtserror.MultiError{} + for _, accountID := range accountIDs { + if err := p.timelineStatusForAccount(ctx, status, accountID); err != nil { + errors.Append(err) } - }(errs) - - // wait til all functions have returned and then close the error channel - wg.Wait() - close(errors) + } - if len(errs) != 0 { - // we have at least one error - return fmt.Errorf("timelineStatus: one or more errors timelining statuses: %s", strings.Join(errs, ";")) + if len(errors) != 0 { + return fmt.Errorf("timelineStatus: one or more errors timelining statuses: %w", errors.Combine()) } return nil @@ -462,46 +446,38 @@ func (p *Processor) timelineStatus(ctx context.Context, status *gtsmodel.Status) // // If the status was inserted into the home timeline of the given account, // it will also be streamed via websockets to the user. -func (p *Processor) timelineStatusForAccount(ctx context.Context, status *gtsmodel.Status, accountID string, errors chan error, wg *sync.WaitGroup) { - defer wg.Done() - +func (p *Processor) timelineStatusForAccount(ctx context.Context, status *gtsmodel.Status, accountID string) error { // get the timeline owner account timelineAccount, err := p.state.DB.GetAccountByID(ctx, accountID) if err != nil { - errors <- fmt.Errorf("timelineStatusForAccount: error getting account for timeline with id %s: %s", accountID, err) - return + return fmt.Errorf("timelineStatusForAccount: error getting account for timeline with id %s: %w", accountID, err) } // make sure the status is timelineable - timelineable, err := p.filter.StatusHometimelineable(ctx, status, timelineAccount) - if err != nil { - errors <- fmt.Errorf("timelineStatusForAccount: error getting timelineability for status for timeline with id %s: %s", accountID, err) - return - } - - if !timelineable { - return + if timelineable, err := p.filter.StatusHometimelineable(ctx, status, timelineAccount); err != nil { + return fmt.Errorf("timelineStatusForAccount: error getting timelineability for status for timeline with id %s: %w", accountID, err) + } else if !timelineable { + return nil } // stick the status in the timeline for the account and then immediately prepare it so they can see it right away - inserted, err := p.statusTimelines.IngestAndPrepare(ctx, status, timelineAccount.ID) - if err != nil { - errors <- fmt.Errorf("timelineStatusForAccount: error ingesting status %s: %s", status.ID, err) - return + if inserted, err := p.statusTimelines.IngestAndPrepare(ctx, status, timelineAccount.ID); err != nil { + return fmt.Errorf("timelineStatusForAccount: error ingesting status %s: %w", status.ID, err) + } else if !inserted { + return nil } // the status was inserted so stream it to the user - if inserted { - apiStatus, err := p.tc.StatusToAPIStatus(ctx, status, timelineAccount) - if err != nil { - errors <- fmt.Errorf("timelineStatusForAccount: error converting status %s to frontend representation: %s", status.ID, err) - return - } + apiStatus, err := p.tc.StatusToAPIStatus(ctx, status, timelineAccount) + if err != nil { + return fmt.Errorf("timelineStatusForAccount: error converting status %s to frontend representation: %w", status.ID, err) + } - if err := p.stream.Update(apiStatus, timelineAccount, stream.TimelineHome); err != nil { - errors <- fmt.Errorf("timelineStatusForAccount: error streaming status %s: %s", status.ID, err) - } + if err := p.stream.Update(apiStatus, timelineAccount, stream.TimelineHome); err != nil { + return fmt.Errorf("timelineStatusForAccount: error streaming update for status %s: %w", status.ID, err) } + + return nil } // deleteStatusFromTimelines completely removes the given status from all timelines. @@ -544,12 +520,17 @@ func (p *Processor) wipeStatus(ctx context.Context, statusToDelete *gtsmodel.Sta } // delete all notification entries generated by this status - if err := p.state.DB.DeleteWhere(ctx, []db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.Notification{}); err != nil { + if err := p.state.DB.DeleteNotificationsForStatus(ctx, statusToDelete.ID); err != nil { return err } // delete all bookmarks that point to this status - if err := p.state.DB.DeleteWhere(ctx, []db.Where{{Key: "status_id", Value: statusToDelete.ID}}, &[]*gtsmodel.StatusBookmark{}); err != nil { + if err := p.state.DB.DeleteStatusBookmarksForStatus(ctx, statusToDelete.ID); err != nil { + return err + } + + // delete all faves of this status + if err := p.state.DB.DeleteStatusFavesForStatus(ctx, statusToDelete.ID); err != nil { return err } |