summaryrefslogtreecommitdiff
path: root/internal/processing/workers
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2024-03-13 13:53:29 +0100
committerLibravatar GitHub <noreply@github.com>2024-03-13 13:53:29 +0100
commitab2d063fcb04f241a3147c843a021491f5fc0a55 (patch)
tree3d2eff864e8b19d4d9a24f4f1fe92feda8ee4dac /internal/processing/workers
parent[bugfix]: Add missing Link headers in Swagger spec (#2751) (diff)
downloadgotosocial-ab2d063fcb04f241a3147c843a021491f5fc0a55.tar.xz
[feature] Process outgoing Move from clientAPI (#2750)
* prevent moved accounts from taking create-type actions * update move logic * federate move out * indicate on web profile when an account has moved * [docs] Add migration docs section * lock while checking + setting move state * use redirectFollowers func for clientAPI as well * comment typo * linter? i barely know 'er! * Update internal/uris/uri.go Co-authored-by: Daenney <daenney@users.noreply.github.com> * add a couple tests for move * fix little mistake exposed by tests (thanks tests) * ensure Move marked as successful * attach shared util funcs to struct * lock whole account when doing move * move moving check to after error check * replace repeated text with error func * linterrrrrr!!!! * catch self follow case --------- Co-authored-by: Daenney <daenney@users.noreply.github.com>
Diffstat (limited to 'internal/processing/workers')
-rw-r--r--internal/processing/workers/federate.go66
-rw-r--r--internal/processing/workers/fromclientapi.go53
-rw-r--r--internal/processing/workers/fromfediapi.go12
-rw-r--r--internal/processing/workers/fromfediapi_move.go95
-rw-r--r--internal/processing/workers/util.go240
-rw-r--r--internal/processing/workers/wipestatus.go135
-rw-r--r--internal/processing/workers/workers.go36
7 files changed, 377 insertions, 260 deletions
diff --git a/internal/processing/workers/federate.go b/internal/processing/workers/federate.go
index aacb8dcc8..9fdb8f662 100644
--- a/internal/processing/workers/federate.go
+++ b/internal/processing/workers/federate.go
@@ -23,6 +23,7 @@ import (
"github.com/superseriousbusiness/activity/pub"
"github.com/superseriousbusiness/activity/streams"
+ "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/federation"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
@@ -954,3 +955,68 @@ func (f *federate) Flag(ctx context.Context, report *gtsmodel.Report) error {
return nil
}
+
+func (f *federate) MoveAccount(ctx context.Context, account *gtsmodel.Account) error {
+ // Do nothing if it's not our
+ // account that's been moved.
+ if !account.IsLocal() {
+ return nil
+ }
+
+ // Parse relevant URI(s).
+ outboxIRI, err := parseURI(account.OutboxURI)
+ if err != nil {
+ return err
+ }
+
+ // Actor doing the Move.
+ actorIRI := account.Move.Origin
+
+ // Destination Actor of the Move.
+ targetIRI := account.Move.Target
+
+ followersIRI, err := parseURI(account.FollowersURI)
+ if err != nil {
+ return err
+ }
+
+ publicIRI, err := parseURI(pub.PublicActivityPubIRI)
+ if err != nil {
+ return err
+ }
+
+ // Create a new move.
+ move := streams.NewActivityStreamsMove()
+
+ // Set the Move ID.
+ if err := ap.SetJSONLDIdStr(move, account.Move.URI); err != nil {
+ return err
+ }
+
+ // Set the Actor for the Move.
+ ap.AppendActorIRIs(move, actorIRI)
+
+ // Set the account's IRI as the 'object' property.
+ ap.AppendObjectIRIs(move, actorIRI)
+
+ // Set the target's IRI as the 'target' property.
+ ap.AppendTargetIRIs(move, targetIRI)
+
+ // Address the move To followers.
+ ap.AppendTo(move, followersIRI)
+
+ // Address the move CC public.
+ ap.AppendCc(move, publicIRI)
+
+ // Send the Move via the Actor's outbox.
+ if _, err := f.FederatingActor().Send(
+ ctx, outboxIRI, move,
+ ); err != nil {
+ return gtserror.Newf(
+ "error sending activity %T via outbox %s: %w",
+ move, outboxIRI, err,
+ )
+ }
+
+ return nil
+}
diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go
index 05b9acc1f..c7e78fee2 100644
--- a/internal/processing/workers/fromclientapi.go
+++ b/internal/processing/workers/fromclientapi.go
@@ -39,12 +39,12 @@ import (
// specifically for messages originating
// from the client/REST API.
type clientAPI struct {
- state *state.State
- converter *typeutils.Converter
- surface *surface
- federate *federate
- wipeStatus wipeStatus
- account *account.Processor
+ state *state.State
+ converter *typeutils.Converter
+ surface *surface
+ federate *federate
+ account *account.Processor
+ utilF *utilF
}
func (p *Processor) EnqueueClientAPI(cctx context.Context, msgs ...messages.FromClientAPI) {
@@ -194,6 +194,15 @@ func (p *Processor) ProcessFromClientAPI(ctx context.Context, cMsg messages.From
case ap.ObjectProfile:
return p.clientAPI.ReportAccount(ctx, cMsg)
}
+
+ // MOVE SOMETHING
+ case ap.ActivityMove:
+ switch cMsg.APObjectType { //nolint:gocritic
+
+ // MOVE PROFILE/ACCOUNT
+ case ap.ObjectProfile, ap.ActorPerson:
+ return p.clientAPI.MoveAccount(ctx, cMsg)
+ }
}
return gtserror.Newf("unhandled: %s %s", cMsg.APActivityType, cMsg.APObjectType)
@@ -576,7 +585,7 @@ func (p *clientAPI) DeleteStatus(ctx context.Context, cMsg messages.FromClientAP
return gtserror.Newf("db error populating status: %w", err)
}
- if err := p.wipeStatus(ctx, status, deleteAttachments); err != nil {
+ if err := p.utilF.wipeStatus(ctx, status, deleteAttachments); err != nil {
log.Errorf(ctx, "error wiping status: %v", err)
}
@@ -641,3 +650,33 @@ func (p *clientAPI) ReportAccount(ctx context.Context, cMsg messages.FromClientA
return nil
}
+
+func (p *clientAPI) MoveAccount(ctx context.Context, cMsg messages.FromClientAPI) error {
+ // Redirect each local follower of
+ // OriginAccount to follow move target.
+ p.utilF.redirectFollowers(ctx, cMsg.OriginAccount, cMsg.TargetAccount)
+
+ // At this point, we know OriginAccount has the
+ // Move set on it. Just make sure it's populated.
+ if err := p.state.DB.PopulateMove(ctx, cMsg.OriginAccount.Move); err != nil {
+ return gtserror.Newf("error populating Move: %w", err)
+ }
+
+ // Now send the Move message out to
+ // OriginAccount's (remote) followers.
+ if err := p.federate.MoveAccount(ctx, cMsg.OriginAccount); err != nil {
+ return gtserror.Newf("error federating account move: %w", err)
+ }
+
+ // Mark the move attempt as successful.
+ cMsg.OriginAccount.Move.SucceededAt = cMsg.OriginAccount.Move.AttemptedAt
+ if err := p.state.DB.UpdateMove(
+ ctx,
+ cMsg.OriginAccount.Move,
+ "succeeded_at",
+ ); err != nil {
+ return gtserror.Newf("error marking move as successful: %w", err)
+ }
+
+ return nil
+}
diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go
index 62cb58c83..2fc3b4b26 100644
--- a/internal/processing/workers/fromfediapi.go
+++ b/internal/processing/workers/fromfediapi.go
@@ -39,11 +39,11 @@ import (
// specifically for messages originating
// from the federation/ActivityPub API.
type fediAPI struct {
- state *state.State
- surface *surface
- federate *federate
- wipeStatus wipeStatus
- account *account.Processor
+ state *state.State
+ surface *surface
+ federate *federate
+ account *account.Processor
+ utilF *utilF
}
func (p *Processor) EnqueueFediAPI(cctx context.Context, msgs ...messages.FromFediAPI) {
@@ -563,7 +563,7 @@ func (p *fediAPI) DeleteStatus(ctx context.Context, fMsg messages.FromFediAPI) e
return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel)
}
- if err := p.wipeStatus(ctx, status, deleteAttachments); err != nil {
+ if err := p.utilF.wipeStatus(ctx, status, deleteAttachments); err != nil {
log.Errorf(ctx, "error wiping status: %v", err)
}
diff --git a/internal/processing/workers/fromfediapi_move.go b/internal/processing/workers/fromfediapi_move.go
index 2223a21f5..0188a5d14 100644
--- a/internal/processing/workers/fromfediapi_move.go
+++ b/internal/processing/workers/fromfediapi_move.go
@@ -22,7 +22,6 @@ import (
"errors"
"time"
- apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
@@ -380,7 +379,7 @@ func (p *fediAPI) MoveAccount(ctx context.Context, fMsg messages.FromFediAPI) er
// Transfer originAcct's followers
// on this instance to targetAcct.
- redirectOK := p.RedirectAccountFollowers(
+ redirectOK := p.utilF.redirectFollowers(
ctx,
originAcct,
targetAcct,
@@ -422,98 +421,6 @@ func (p *fediAPI) MoveAccount(ctx context.Context, fMsg messages.FromFediAPI) er
return nil
}
-// RedirectAccountFollowers redirects all local
-// followers of originAcct to targetAcct.
-//
-// Both accounts must be fully dereferenced
-// already, and the Move must be valid.
-//
-// Callers to this function MUST have obtained
-// a lock already by calling FedLocks.Lock.
-//
-// Return bool will be true if all goes OK.
-func (p *fediAPI) RedirectAccountFollowers(
- ctx context.Context,
- originAcct *gtsmodel.Account,
- targetAcct *gtsmodel.Account,
-) bool {
- // Any local followers of originAcct should
- // send follow requests to targetAcct instead,
- // and have followers of originAcct removed.
- //
- // Select local followers with barebones, since
- // we only need follow.Account and we can get
- // that ourselves.
- followers, err := p.state.DB.GetAccountLocalFollowers(
- gtscontext.SetBarebones(ctx),
- originAcct.ID,
- )
- if err != nil && !errors.Is(err, db.ErrNoEntries) {
- log.Errorf(ctx,
- "db error getting follows targeting originAcct: %v",
- err,
- )
- return false
- }
-
- for _, follow := range followers {
- // Fetch the local account that
- // owns the follow targeting originAcct.
- if follow.Account, err = p.state.DB.GetAccountByID(
- gtscontext.SetBarebones(ctx),
- follow.AccountID,
- ); err != nil {
- log.Errorf(ctx,
- "db error getting follow account %s: %v",
- follow.AccountID, err,
- )
- return false
- }
-
- // Use the account processor FollowCreate
- // function to send off the new follow,
- // carrying over the Reblogs and Notify
- // values from the old follow to the new.
- //
- // This will also handle cases where our
- // account has already followed the target
- // account, by just updating the existing
- // follow of target account.
- if _, err := p.account.FollowCreate(
- ctx,
- follow.Account,
- &apimodel.AccountFollowRequest{
- ID: targetAcct.ID,
- Reblogs: follow.ShowReblogs,
- Notify: follow.Notify,
- },
- ); err != nil {
- log.Errorf(ctx,
- "error creating new follow for account %s: %v",
- follow.AccountID, err,
- )
- return false
- }
-
- // New follow is in the process of
- // sending, remove the existing follow.
- // This will send out an Undo Activity for each Follow.
- if _, err := p.account.FollowRemove(
- ctx,
- follow.Account,
- follow.TargetAccountID,
- ); err != nil {
- log.Errorf(ctx,
- "error removing old follow for account %s: %v",
- follow.AccountID, err,
- )
- return false
- }
- }
-
- return true
-}
-
// RemoveAccountFollowing removes all
// follows owned by the move originAcct.
//
diff --git a/internal/processing/workers/util.go b/internal/processing/workers/util.go
new file mode 100644
index 000000000..a38ecd336
--- /dev/null
+++ b/internal/processing/workers/util.go
@@ -0,0 +1,240 @@
+// GoToSocial
+// Copyright (C) GoToSocial Authors admin@gotosocial.org
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package workers
+
+import (
+ "context"
+ "errors"
+
+ apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
+ "github.com/superseriousbusiness/gotosocial/internal/db"
+ "github.com/superseriousbusiness/gotosocial/internal/gtscontext"
+ "github.com/superseriousbusiness/gotosocial/internal/gtserror"
+ "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
+ "github.com/superseriousbusiness/gotosocial/internal/log"
+ "github.com/superseriousbusiness/gotosocial/internal/processing/account"
+ "github.com/superseriousbusiness/gotosocial/internal/processing/media"
+ "github.com/superseriousbusiness/gotosocial/internal/state"
+)
+
+// utilF wraps util functions used by both
+// the fromClientAPI and fromFediAPI functions.
+type utilF struct {
+ state *state.State
+ media *media.Processor
+ account *account.Processor
+ surface *surface
+}
+
+// wipeStatus encapsulates common logic
+// used to totally delete a status + all
+// its attachments, notifications, boosts,
+// and timeline entries.
+func (u *utilF) wipeStatus(
+ ctx context.Context,
+ statusToDelete *gtsmodel.Status,
+ deleteAttachments bool,
+) error {
+ var errs gtserror.MultiError
+
+ // Either delete all attachments for this status,
+ // or simply unattach + clean them separately later.
+ //
+ // Reason to unattach rather than delete is that
+ // the poster might want to reattach them to another
+ // status immediately (in case of delete + redraft)
+ if deleteAttachments {
+ // todo:u.state.DB.DeleteAttachmentsForStatus
+ for _, id := range statusToDelete.AttachmentIDs {
+ if err := u.media.Delete(ctx, id); err != nil {
+ errs.Appendf("error deleting media: %w", err)
+ }
+ }
+ } else {
+ // todo:u.state.DB.UnattachAttachmentsForStatus
+ for _, id := range statusToDelete.AttachmentIDs {
+ if _, err := u.media.Unattach(ctx, statusToDelete.Account, id); err != nil {
+ errs.Appendf("error unattaching media: %w", err)
+ }
+ }
+ }
+
+ // delete all mention entries generated by this status
+ // todo:u.state.DB.DeleteMentionsForStatus
+ for _, id := range statusToDelete.MentionIDs {
+ if err := u.state.DB.DeleteMentionByID(ctx, id); err != nil {
+ errs.Appendf("error deleting status mention: %w", err)
+ }
+ }
+
+ // delete all notification entries generated by this status
+ if err := u.state.DB.DeleteNotificationsForStatus(ctx, statusToDelete.ID); err != nil {
+ errs.Appendf("error deleting status notifications: %w", err)
+ }
+
+ // delete all bookmarks that point to this status
+ if err := u.state.DB.DeleteStatusBookmarksForStatus(ctx, statusToDelete.ID); err != nil {
+ errs.Appendf("error deleting status bookmarks: %w", err)
+ }
+
+ // delete all faves of this status
+ if err := u.state.DB.DeleteStatusFavesForStatus(ctx, statusToDelete.ID); err != nil {
+ errs.Appendf("error deleting status faves: %w", err)
+ }
+
+ if pollID := statusToDelete.PollID; pollID != "" {
+ // Delete this poll by ID from the database.
+ if err := u.state.DB.DeletePollByID(ctx, pollID); err != nil {
+ errs.Appendf("error deleting status poll: %w", err)
+ }
+
+ // Delete any poll votes pointing to this poll ID.
+ if err := u.state.DB.DeletePollVotes(ctx, pollID); err != nil {
+ errs.Appendf("error deleting status poll votes: %w", err)
+ }
+
+ // Cancel any scheduled expiry task for poll.
+ _ = u.state.Workers.Scheduler.Cancel(pollID)
+ }
+
+ // delete all boosts for this status + remove them from timelines
+ boosts, err := u.state.DB.GetStatusBoosts(
+ // we MUST set a barebones context here,
+ // as depending on where it came from the
+ // original BoostOf may already be gone.
+ gtscontext.SetBarebones(ctx),
+ statusToDelete.ID)
+ if err != nil {
+ errs.Appendf("error fetching status boosts: %w", err)
+ }
+
+ for _, boost := range boosts {
+ if err := u.surface.deleteStatusFromTimelines(ctx, boost.ID); err != nil {
+ errs.Appendf("error deleting boost from timelines: %w", err)
+ }
+ if err := u.state.DB.DeleteStatusByID(ctx, boost.ID); err != nil {
+ errs.Appendf("error deleting boost: %w", err)
+ }
+ }
+
+ // delete this status from any and all timelines
+ if err := u.surface.deleteStatusFromTimelines(ctx, statusToDelete.ID); err != nil {
+ errs.Appendf("error deleting status from timelines: %w", err)
+ }
+
+ // finally, delete the status itself
+ if err := u.state.DB.DeleteStatusByID(ctx, statusToDelete.ID); err != nil {
+ errs.Appendf("error deleting status: %w", err)
+ }
+
+ return errs.Combine()
+}
+
+// redirectFollowers redirects all local
+// followers of originAcct to targetAcct.
+//
+// Both accounts must be fully dereferenced
+// already, and the Move must be valid.
+//
+// Return bool will be true if all goes OK.
+func (u *utilF) redirectFollowers(
+ ctx context.Context,
+ originAcct *gtsmodel.Account,
+ targetAcct *gtsmodel.Account,
+) bool {
+ // Any local followers of originAcct should
+ // send follow requests to targetAcct instead,
+ // and have followers of originAcct removed.
+ //
+ // Select local followers with barebones, since
+ // we only need follow.Account and we can get
+ // that ourselves.
+ followers, err := u.state.DB.GetAccountLocalFollowers(
+ gtscontext.SetBarebones(ctx),
+ originAcct.ID,
+ )
+ if err != nil && !errors.Is(err, db.ErrNoEntries) {
+ log.Errorf(ctx,
+ "db error getting follows targeting originAcct: %v",
+ err,
+ )
+ return false
+ }
+
+ for _, follow := range followers {
+ // Fetch the local account that
+ // owns the follow targeting originAcct.
+ if follow.Account, err = u.state.DB.GetAccountByID(
+ gtscontext.SetBarebones(ctx),
+ follow.AccountID,
+ ); err != nil {
+ log.Errorf(ctx,
+ "db error getting follow account %s: %v",
+ follow.AccountID, err,
+ )
+ return false
+ }
+
+ // Use the account processor FollowCreate
+ // function to send off the new follow,
+ // carrying over the Reblogs and Notify
+ // values from the old follow to the new.
+ //
+ // This will also handle cases where our
+ // account has already followed the target
+ // account, by just updating the existing
+ // follow of target account.
+ //
+ // Also, ensure new follow wouldn't be a
+ // self follow, since that will error.
+ if follow.AccountID != targetAcct.ID {
+ if _, err := u.account.FollowCreate(
+ ctx,
+ follow.Account,
+ &apimodel.AccountFollowRequest{
+ ID: targetAcct.ID,
+ Reblogs: follow.ShowReblogs,
+ Notify: follow.Notify,
+ },
+ ); err != nil {
+ log.Errorf(ctx,
+ "error creating new follow for account %s: %v",
+ follow.AccountID, err,
+ )
+ return false
+ }
+ }
+
+ // New follow is in the process of
+ // sending, remove the existing follow.
+ // This will send out an Undo Activity for each Follow.
+ if _, err := u.account.FollowRemove(
+ ctx,
+ follow.Account,
+ follow.TargetAccountID,
+ ); err != nil {
+ log.Errorf(ctx,
+ "error removing old follow for account %s: %v",
+ follow.AccountID, err,
+ )
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/internal/processing/workers/wipestatus.go b/internal/processing/workers/wipestatus.go
deleted file mode 100644
index 90a037928..000000000
--- a/internal/processing/workers/wipestatus.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// GoToSocial
-// Copyright (C) GoToSocial Authors admin@gotosocial.org
-// SPDX-License-Identifier: AGPL-3.0-or-later
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package workers
-
-import (
- "context"
-
- "github.com/superseriousbusiness/gotosocial/internal/gtscontext"
- "github.com/superseriousbusiness/gotosocial/internal/gtserror"
- "github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
- "github.com/superseriousbusiness/gotosocial/internal/processing/media"
- "github.com/superseriousbusiness/gotosocial/internal/state"
-)
-
-// wipeStatus encapsulates common logic used to totally delete a status
-// + all its attachments, notifications, boosts, and timeline entries.
-type wipeStatus func(context.Context, *gtsmodel.Status, bool) error
-
-// wipeStatusF returns a wipeStatus util function.
-func wipeStatusF(state *state.State, media *media.Processor, surface *surface) wipeStatus {
- return func(
- ctx context.Context,
- statusToDelete *gtsmodel.Status,
- deleteAttachments bool,
- ) error {
- var errs gtserror.MultiError
-
- // Either delete all attachments for this status,
- // or simply unattach + clean them separately later.
- //
- // Reason to unattach rather than delete is that
- // the poster might want to reattach them to another
- // status immediately (in case of delete + redraft)
- if deleteAttachments {
- // todo:state.DB.DeleteAttachmentsForStatus
- for _, id := range statusToDelete.AttachmentIDs {
- if err := media.Delete(ctx, id); err != nil {
- errs.Appendf("error deleting media: %w", err)
- }
- }
- } else {
- // todo:state.DB.UnattachAttachmentsForStatus
- for _, id := range statusToDelete.AttachmentIDs {
- if _, err := media.Unattach(ctx, statusToDelete.Account, id); err != nil {
- errs.Appendf("error unattaching media: %w", err)
- }
- }
- }
-
- // delete all mention entries generated by this status
- // todo:state.DB.DeleteMentionsForStatus
- for _, id := range statusToDelete.MentionIDs {
- if err := state.DB.DeleteMentionByID(ctx, id); err != nil {
- errs.Appendf("error deleting status mention: %w", err)
- }
- }
-
- // delete all notification entries generated by this status
- if err := state.DB.DeleteNotificationsForStatus(ctx, statusToDelete.ID); err != nil {
- errs.Appendf("error deleting status notifications: %w", err)
- }
-
- // delete all bookmarks that point to this status
- if err := state.DB.DeleteStatusBookmarksForStatus(ctx, statusToDelete.ID); err != nil {
- errs.Appendf("error deleting status bookmarks: %w", err)
- }
-
- // delete all faves of this status
- if err := state.DB.DeleteStatusFavesForStatus(ctx, statusToDelete.ID); err != nil {
- errs.Appendf("error deleting status faves: %w", err)
- }
-
- if pollID := statusToDelete.PollID; pollID != "" {
- // Delete this poll by ID from the database.
- if err := state.DB.DeletePollByID(ctx, pollID); err != nil {
- errs.Appendf("error deleting status poll: %w", err)
- }
-
- // Delete any poll votes pointing to this poll ID.
- if err := state.DB.DeletePollVotes(ctx, pollID); err != nil {
- errs.Appendf("error deleting status poll votes: %w", err)
- }
-
- // Cancel any scheduled expiry task for poll.
- _ = state.Workers.Scheduler.Cancel(pollID)
- }
-
- // delete all boosts for this status + remove them from timelines
- boosts, err := state.DB.GetStatusBoosts(
- // we MUST set a barebones context here,
- // as depending on where it came from the
- // original BoostOf may already be gone.
- gtscontext.SetBarebones(ctx),
- statusToDelete.ID)
- if err != nil {
- errs.Appendf("error fetching status boosts: %w", err)
- }
-
- for _, boost := range boosts {
- if err := surface.deleteStatusFromTimelines(ctx, boost.ID); err != nil {
- errs.Appendf("error deleting boost from timelines: %w", err)
- }
- if err := state.DB.DeleteStatusByID(ctx, boost.ID); err != nil {
- errs.Appendf("error deleting boost: %w", err)
- }
- }
-
- // delete this status from any and all timelines
- if err := surface.deleteStatusFromTimelines(ctx, statusToDelete.ID); err != nil {
- errs.Appendf("error deleting status from timelines: %w", err)
- }
-
- // finally, delete the status itself
- if err := state.DB.DeleteStatusByID(ctx, statusToDelete.ID); err != nil {
- errs.Appendf("error deleting status: %w", err)
- }
-
- return errs.Combine()
- }
-}
diff --git a/internal/processing/workers/workers.go b/internal/processing/workers/workers.go
index c0612de27..8488e501c 100644
--- a/internal/processing/workers/workers.go
+++ b/internal/processing/workers/workers.go
@@ -63,30 +63,30 @@ func New(
converter: converter,
}
- // Init shared logic wipe
- // status util func.
- wipeStatus := wipeStatusF(
- state,
- media,
- surface,
- )
+ // Init shared util funcs.
+ utilF := &utilF{
+ state: state,
+ media: media,
+ account: account,
+ surface: surface,
+ }
return Processor{
workers: &state.Workers,
clientAPI: &clientAPI{
- state: state,
- converter: converter,
- surface: surface,
- federate: federate,
- wipeStatus: wipeStatus,
- account: account,
+ state: state,
+ converter: converter,
+ surface: surface,
+ federate: federate,
+ account: account,
+ utilF: utilF,
},
fediAPI: &fediAPI{
- state: state,
- surface: surface,
- federate: federate,
- wipeStatus: wipeStatus,
- account: account,
+ state: state,
+ surface: surface,
+ federate: federate,
+ account: account,
+ utilF: utilF,
},
}
}