gotosocial/internal/processing/workers/wipestatus.go
tobi 9770d54237
[feature] List replies policy, refactor async workers (#2087)
* Add/update some DB functions.

* move async workers into subprocessor

* rename FromFederator -> FromFediAPI

* update home timeline check to include check for current status first before moving to parent status

* change streamMap to pointer to mollify linter

* update followtoas func signature

* fix merge

* remove errant debug log

* don't use separate errs.Combine() check to wrap errs

* wrap parts of workers functionality in sub-structs

* populate report using new db funcs

* embed federator (tiny bit tidier)

* flesh out error msg, add continue(!)

* fix other error messages to be more specific

* better, nicer

* give parseURI util function a bit more util

* missing headers

* use pointers for subprocessors
2023-08-09 19:14:33 +02:00

120 lines
4.3 KiB
Go

// 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 {
errs := new(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 _, a := range statusToDelete.AttachmentIDs {
if err := media.Delete(ctx, a); err != nil {
errs.Appendf("error deleting media: %w", err)
}
}
} else {
// todo:state.DB.UnattachAttachmentsForStatus
for _, a := range statusToDelete.AttachmentIDs {
if _, err := media.Unattach(ctx, statusToDelete.Account, a); 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)
}
// 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 _, b := range boosts {
if err := surface.deleteStatusFromTimelines(ctx, b.ID); err != nil {
errs.Appendf("error deleting boost from timelines: %w", err)
}
if err := state.DB.DeleteStatusByID(ctx, b.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()
}
}