diff options
Diffstat (limited to 'internal/processing/workers')
| -rw-r--r-- | internal/processing/workers/fromclientapi.go | 62 | ||||
| -rw-r--r-- | internal/processing/workers/fromfediapi.go | 151 | ||||
| -rw-r--r-- | internal/processing/workers/util.go | 99 | ||||
| -rw-r--r-- | internal/processing/workers/workers.go | 9 | 
4 files changed, 260 insertions, 61 deletions
| diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go index c723a6001..c8bc8352f 100644 --- a/internal/processing/workers/fromclientapi.go +++ b/internal/processing/workers/fromclientapi.go @@ -911,11 +911,6 @@ func (p *clientAPI) UndoAnnounce(ctx context.Context, cMsg *messages.FromClientA  }  func (p *clientAPI) DeleteStatus(ctx context.Context, cMsg *messages.FromClientAPI) error { -	// Don't delete attachments, just unattach them: -	// this request comes from the client API and the -	// poster may want to use attachments again later. -	const deleteAttachments = false -  	status, ok := cMsg.GTSModel.(*gtsmodel.Status)  	if !ok {  		return gtserror.Newf("%T not parseable as *gtsmodel.Status", cMsg.GTSModel) @@ -942,8 +937,22 @@ func (p *clientAPI) DeleteStatus(ctx context.Context, cMsg *messages.FromClientA  	// (stops processing of remote origin data targeting this status).  	p.state.Workers.Federator.Queue.Delete("TargetURI", status.URI) -	// First perform the actual status deletion. -	if err := p.utils.wipeStatus(ctx, status, deleteAttachments); err != nil { +	// Don't delete attachments, just unattach them: +	// this request comes from the client API and the +	// poster may want to use attachments again later. +	const deleteAttachments = false + +	// This is just a deletion, not a Reject, +	// we don't need to take a copy of this status. +	const copyToSinBin = false + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		status, +		deleteAttachments, +		copyToSinBin, +	); err != nil {  		log.Errorf(ctx, "error wiping status: %v", err)  	} @@ -1275,9 +1284,23 @@ func (p *clientAPI) RejectReply(ctx context.Context, cMsg *messages.FromClientAP  		return gtserror.Newf("db error getting rejected reply: %w", err)  	} -	// Totally wipe the status. -	if err := p.utils.wipeStatus(ctx, status, true); err != nil { -		return gtserror.Newf("error wiping status: %w", err) +	// Delete attachments from this status. +	// It's rejected so there's no possibility +	// for the poster to delete + redraft it. +	const deleteAttachments = true + +	// Keep a copy of the status in +	// the sin bin for future review. +	const copyToSinBin = true + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		status, +		deleteAttachments, +		copyToSinBin, +	); err != nil { +		log.Errorf(ctx, "error wiping reply: %v", err)  	}  	return nil @@ -1306,9 +1329,22 @@ func (p *clientAPI) RejectAnnounce(ctx context.Context, cMsg *messages.FromClien  		return gtserror.Newf("db error getting rejected announce: %w", err)  	} -	// Totally wipe the status. -	if err := p.utils.wipeStatus(ctx, boost, true); err != nil { -		return gtserror.Newf("error wiping status: %w", err) +	// Boosts don't have attachments anyway +	// so it doesn't matter what we set here. +	const deleteAttachments = true + +	// This is just a boost, don't +	// keep a copy in the sin bin. +	const copyToSinBin = true + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		boost, +		deleteAttachments, +		copyToSinBin, +	); err != nil { +		log.Errorf(ctx, "error wiping announce: %v", err)  	}  	return nil diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go index 42e5e9db2..d8abaa865 100644 --- a/internal/processing/workers/fromfediapi.go +++ b/internal/processing/workers/fromfediapi.go @@ -27,6 +27,7 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/ap"  	"github.com/superseriousbusiness/gotosocial/internal/db"  	"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing" +	"github.com/superseriousbusiness/gotosocial/internal/gtscontext"  	"github.com/superseriousbusiness/gotosocial/internal/id"  	"github.com/superseriousbusiness/gotosocial/internal/uris" @@ -146,6 +147,23 @@ func (p *Processor) ProcessFromFediAPI(ctx context.Context, fMsg *messages.FromF  			return p.fediAPI.AcceptAnnounce(ctx, fMsg)  		} +	// REJECT SOMETHING +	case ap.ActivityReject: +		switch fMsg.APObjectType { + +		// REJECT LIKE +		case ap.ActivityLike: +			return p.fediAPI.RejectLike(ctx, fMsg) + +		// REJECT NOTE/STATUS (ie., reject a reply) +		case ap.ObjectNote: +			return p.fediAPI.RejectReply(ctx, fMsg) + +		// REJECT BOOST +		case ap.ActivityAnnounce: +			return p.fediAPI.RejectAnnounce(ctx, fMsg) +		} +  	// DELETE SOMETHING  	case ap.ActivityDelete:  		switch fMsg.APObjectType { @@ -878,11 +896,6 @@ func (p *fediAPI) UpdateStatus(ctx context.Context, fMsg *messages.FromFediAPI)  }  func (p *fediAPI) DeleteStatus(ctx context.Context, fMsg *messages.FromFediAPI) error { -	// Delete attachments from this status, since this request -	// comes from the federating API, and there's no way the -	// poster can do a delete + redraft for it on our instance. -	const deleteAttachments = true -  	status, ok := fMsg.GTSModel.(*gtsmodel.Status)  	if !ok {  		return gtserror.Newf("%T not parseable as *gtsmodel.Status", fMsg.GTSModel) @@ -909,8 +922,22 @@ func (p *fediAPI) DeleteStatus(ctx context.Context, fMsg *messages.FromFediAPI)  	// (stops processing of remote origin data targeting this status).  	p.state.Workers.Federator.Queue.Delete("TargetURI", status.URI) -	// First perform the actual status deletion. -	if err := p.utils.wipeStatus(ctx, status, deleteAttachments); err != nil { +	// Delete attachments from this status, since this request +	// comes from the federating API, and there's no way the +	// poster can do a delete + redraft for it on our instance. +	const deleteAttachments = true + +	// This is just a deletion, not a Reject, +	// we don't need to take a copy of this status. +	const copyToSinBin = false + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		status, +		deleteAttachments, +		copyToSinBin, +	); err != nil {  		log.Errorf(ctx, "error wiping status: %v", err)  	} @@ -956,3 +983,113 @@ func (p *fediAPI) DeleteAccount(ctx context.Context, fMsg *messages.FromFediAPI)  	return nil  } + +func (p *fediAPI) RejectLike(ctx context.Context, fMsg *messages.FromFediAPI) error { +	req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest) +	if !ok { +		return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel) +	} + +	// At this point the InteractionRequest should already +	// be in the database, we just need to do side effects. + +	// Send out the Reject. +	if err := p.federate.RejectInteraction(ctx, req); err != nil { +		log.Errorf(ctx, "error federating rejection of like: %v", err) +	} + +	// Get the rejected fave. +	fave, err := p.state.DB.GetStatusFaveByURI( +		gtscontext.SetBarebones(ctx), +		req.InteractionURI, +	) +	if err != nil { +		return gtserror.Newf("db error getting rejected fave: %w", err) +	} + +	// Delete the fave. +	if err := p.state.DB.DeleteStatusFaveByID(ctx, fave.ID); err != nil { +		return gtserror.Newf("db error deleting fave: %w", err) +	} + +	return nil +} + +func (p *fediAPI) RejectReply(ctx context.Context, fMsg *messages.FromFediAPI) error { +	req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest) +	if !ok { +		return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel) +	} + +	// At this point the InteractionRequest should already +	// be in the database, we just need to do side effects. + +	// Get the rejected status. +	status, err := p.state.DB.GetStatusByURI( +		gtscontext.SetBarebones(ctx), +		req.InteractionURI, +	) +	if err != nil { +		return gtserror.Newf("db error getting rejected reply: %w", err) +	} + +	// Delete attachments from this status. +	// It's rejected so there's no possibility +	// for the poster to delete + redraft it. +	const deleteAttachments = true + +	// Keep a copy of the status in +	// the sin bin for future review. +	const copyToSinBin = true + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		status, +		deleteAttachments, +		copyToSinBin, +	); err != nil { +		log.Errorf(ctx, "error wiping reply: %v", err) +	} + +	return nil +} + +func (p *fediAPI) RejectAnnounce(ctx context.Context, fMsg *messages.FromFediAPI) error { +	req, ok := fMsg.GTSModel.(*gtsmodel.InteractionRequest) +	if !ok { +		return gtserror.Newf("%T not parseable as *gtsmodel.InteractionRequest", fMsg.GTSModel) +	} + +	// At this point the InteractionRequest should already +	// be in the database, we just need to do side effects. + +	// Get the rejected boost. +	boost, err := p.state.DB.GetStatusByURI( +		gtscontext.SetBarebones(ctx), +		req.InteractionURI, +	) +	if err != nil { +		return gtserror.Newf("db error getting rejected announce: %w", err) +	} + +	// Boosts don't have attachments anyway +	// so it doesn't matter what we set here. +	const deleteAttachments = true + +	// This is just a boost, don't +	// keep a copy in the sin bin. +	const copyToSinBin = true + +	// Perform the actual status deletion. +	if err := p.utils.wipeStatus( +		ctx, +		boost, +		deleteAttachments, +		copyToSinBin, +	); err != nil { +		log.Errorf(ctx, "error wiping announce: %v", err) +	} + +	return nil +} diff --git a/internal/processing/workers/util.go b/internal/processing/workers/util.go index bb7faffbf..042f4827c 100644 --- a/internal/processing/workers/util.go +++ b/internal/processing/workers/util.go @@ -37,69 +37,90 @@ import (  // util provides util functions used by both  // the fromClientAPI and fromFediAPI functions.  type utils struct { -	state   *state.State -	media   *media.Processor -	account *account.Processor -	surface *Surface +	state     *state.State +	media     *media.Processor +	account   *account.Processor +	surface   *Surface +	converter *typeutils.Converter  } -// wipeStatus encapsulates common logic -// used to totally delete a status + all -// its attachments, notifications, boosts, -// and timeline entries. +// wipeStatus encapsulates common logic used to +// totally delete a status + all its attachments, +// notifications, boosts, and timeline entries. +// +// If deleteAttachments is true, then any status +// attachments will also be deleted, else they +// will just be detached. +// +// If copyToSinBin is true, then a version of the +// status will be put in the `sin_bin_statuses` +// table prior to deletion.  func (u *utils) wipeStatus(  	ctx context.Context, -	statusToDelete *gtsmodel.Status, +	status *gtsmodel.Status,  	deleteAttachments bool, +	copyToSinBin bool,  ) error {  	var errs gtserror.MultiError +	if copyToSinBin { +		// Copy this status to the sin bin before we delete it. +		sbStatus, err := u.converter.StatusToSinBinStatus(ctx, status) +		if err != nil { +			errs.Appendf("error converting status to sinBinStatus: %w", err) +		} else { +			if err := u.state.DB.PutSinBinStatus(ctx, sbStatus); err != nil { +				errs.Appendf("db error storing sinBinStatus: %w", err) +			} +		} +	} +  	// Either delete all attachments for this status, -	// or simply unattach + clean them separately later. +	// or simply detach + 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) +	// Reason to detach rather than delete is that +	// the author 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 { +		for _, id := range status.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 { +		for _, id := range status.AttachmentIDs { +			if _, err := u.media.Unattach(ctx, status.Account, id); err != nil {  				errs.Appendf("error unattaching media: %w", err)  			}  		}  	} -	// delete all mention entries generated by this status +	// Delete all mentions generated by this status.  	// todo:u.state.DB.DeleteMentionsForStatus -	for _, id := range statusToDelete.MentionIDs { +	for _, id := range status.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 { +	// Delete all notifications generated by this status. +	if err := u.state.DB.DeleteNotificationsForStatus(ctx, status.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 { +	// Delete all bookmarks of this status. +	if err := u.state.DB.DeleteStatusBookmarksForStatus(ctx, status.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 { +	// Delete all faves of this status. +	if err := u.state.DB.DeleteStatusFavesForStatus(ctx, status.ID); err != nil {  		errs.Appendf("error deleting status faves: %w", err)  	} -	if pollID := statusToDelete.PollID; pollID != "" { +	if pollID := status.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) @@ -114,38 +135,42 @@ func (u *utils) wipeStatus(  		_ = u.state.Workers.Scheduler.Cancel(pollID)  	} -	// delete all boosts for this status + remove them from timelines +	// Get all boost of this status so that we can +	// delete those boosts + remove them from timelines.  	boosts, err := u.state.DB.GetStatusBoosts( -		// we MUST set a barebones context here, +		// 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) +		status.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) -		} +		// Delete the boost itself.  		if err := u.state.DB.DeleteStatusByID(ctx, boost.ID); err != nil {  			errs.Appendf("error deleting boost: %w", err)  		} + +		// Remove the boost from any and all timelines. +		if err := u.surface.deleteStatusFromTimelines(ctx, boost.ID); err != nil { +			errs.Appendf("error deleting boost from timelines: %w", err) +		}  	} -	// delete this status from any and all timelines -	if err := u.surface.deleteStatusFromTimelines(ctx, statusToDelete.ID); err != nil { +	// Delete the status itself from any and all timelines. +	if err := u.surface.deleteStatusFromTimelines(ctx, status.ID); err != nil {  		errs.Appendf("error deleting status from timelines: %w", err)  	} -	// delete this status from any conversations that it's part of -	if err := u.state.DB.DeleteStatusFromConversations(ctx, statusToDelete.ID); err != nil { +	// Delete this status from any conversations it's part of. +	if err := u.state.DB.DeleteStatusFromConversations(ctx, status.ID); err != nil {  		errs.Appendf("error deleting status from conversations: %w", err)  	} -	// finally, delete the status itself -	if err := u.state.DB.DeleteStatusByID(ctx, statusToDelete.ID); err != nil { +	// Finally delete the status itself. +	if err := u.state.DB.DeleteStatusByID(ctx, status.ID); err != nil {  		errs.Appendf("error deleting status: %w", err)  	} diff --git a/internal/processing/workers/workers.go b/internal/processing/workers/workers.go index d4b525783..ad673481b 100644 --- a/internal/processing/workers/workers.go +++ b/internal/processing/workers/workers.go @@ -70,10 +70,11 @@ func New(  	// Init shared util funcs.  	utils := &utils{ -		state:   state, -		media:   media, -		account: account, -		surface: surface, +		state:     state, +		media:     media, +		account:   account, +		surface:   surface, +		converter: converter,  	}  	return Processor{ | 
