mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 20:02:24 -05:00 
			
		
		
		
	[feature] Federate interaction policies + Accepts; enforce policies (#3138)
* [feature] Federate interaction policies + Accepts; enforce policies * use Acceptable type * fix index * remove appendIRIStrs * add GetAccept federatingdb function * lock on object IRI
This commit is contained in:
		
					parent
					
						
							
								f8d399cf6a
							
						
					
				
			
			
				commit
				
					
						8ab2b19a94
					
				
			
		
					 42 changed files with 3541 additions and 254 deletions
				
			
		|  | @ -32,6 +32,62 @@ import ( | |||
| 	"github.com/superseriousbusiness/gotosocial/internal/util" | ||||
| ) | ||||
| 
 | ||||
| // notifyPendingReply notifies the account replied-to | ||||
| // by the given status that they have a new reply, | ||||
| // and that approval is pending. | ||||
| func (s *Surface) notifyPendingReply( | ||||
| 	ctx context.Context, | ||||
| 	status *gtsmodel.Status, | ||||
| ) error { | ||||
| 	// Beforehand, ensure the passed status is fully populated. | ||||
| 	if err := s.State.DB.PopulateStatus(ctx, status); err != nil { | ||||
| 		return gtserror.Newf("error populating status %s: %w", status.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if status.InReplyToAccount.IsRemote() { | ||||
| 		// Don't notify | ||||
| 		// remote accounts. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	if status.AccountID == status.InReplyToAccountID { | ||||
| 		// Don't notify | ||||
| 		// self-replies. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Ensure thread not muted | ||||
| 	// by replied-to account. | ||||
| 	muted, err := s.State.DB.IsThreadMutedByAccount( | ||||
| 		ctx, | ||||
| 		status.ThreadID, | ||||
| 		status.InReplyToAccountID, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return gtserror.Newf("error checking status thread mute %s: %w", status.ThreadID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if muted { | ||||
| 		// The replied-to account | ||||
| 		// has muted the thread. | ||||
| 		// Don't pester them. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// notify mentioned | ||||
| 	// by status author. | ||||
| 	if err := s.Notify(ctx, | ||||
| 		gtsmodel.NotificationPendingReply, | ||||
| 		status.InReplyToAccount, | ||||
| 		status.Account, | ||||
| 		status.ID, | ||||
| 	); err != nil { | ||||
| 		return gtserror.Newf("error notifying replied-to account %s: %w", status.InReplyToAccountID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // notifyMentions iterates through mentions on the | ||||
| // given status, and notifies each mentioned account | ||||
| // that they have a new mention. | ||||
|  | @ -181,36 +237,13 @@ func (s *Surface) notifyFave( | |||
| 	ctx context.Context, | ||||
| 	fave *gtsmodel.StatusFave, | ||||
| ) error { | ||||
| 	if fave.TargetAccountID == fave.AccountID { | ||||
| 		// Self-fave, nothing to do. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Beforehand, ensure the passed status fave is fully populated. | ||||
| 	if err := s.State.DB.PopulateStatusFave(ctx, fave); err != nil { | ||||
| 		return gtserror.Newf("error populating fave %s: %w", fave.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if fave.TargetAccount.IsRemote() { | ||||
| 		// no need to notify | ||||
| 		// remote accounts. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Ensure favee hasn't | ||||
| 	// muted the thread. | ||||
| 	muted, err := s.State.DB.IsThreadMutedByAccount( | ||||
| 		ctx, | ||||
| 		fave.Status.ThreadID, | ||||
| 		fave.TargetAccountID, | ||||
| 	) | ||||
| 	notifyable, err := s.notifyableFave(ctx, fave) | ||||
| 	if err != nil { | ||||
| 		return gtserror.Newf("error checking status thread mute %s: %w", fave.StatusID, err) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if muted { | ||||
| 		// Favee doesn't want | ||||
| 		// notifs for this thread. | ||||
| 	if !notifyable { | ||||
| 		// Nothing to do. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
|  | @ -228,31 +261,167 @@ func (s *Surface) notifyFave( | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // notifyPendingFave notifies the target of the | ||||
| // given fave that their status has been faved | ||||
| // and that approval is required. | ||||
| func (s *Surface) notifyPendingFave( | ||||
| 	ctx context.Context, | ||||
| 	fave *gtsmodel.StatusFave, | ||||
| ) error { | ||||
| 	notifyable, err := s.notifyableFave(ctx, fave) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if !notifyable { | ||||
| 		// Nothing to do. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// notify status author | ||||
| 	// of fave by account. | ||||
| 	if err := s.Notify(ctx, | ||||
| 		gtsmodel.NotificationPendingFave, | ||||
| 		fave.TargetAccount, | ||||
| 		fave.Account, | ||||
| 		fave.StatusID, | ||||
| 	); err != nil { | ||||
| 		return gtserror.Newf("error notifying status author %s: %w", fave.TargetAccountID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // notifyableFave checks that the given | ||||
| // fave should be notified, taking account | ||||
| // of localness of receiving account, and mutes. | ||||
| func (s *Surface) notifyableFave( | ||||
| 	ctx context.Context, | ||||
| 	fave *gtsmodel.StatusFave, | ||||
| ) (bool, error) { | ||||
| 	if fave.TargetAccountID == fave.AccountID { | ||||
| 		// Self-fave, nothing to do. | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Beforehand, ensure the passed status fave is fully populated. | ||||
| 	if err := s.State.DB.PopulateStatusFave(ctx, fave); err != nil { | ||||
| 		return false, gtserror.Newf("error populating fave %s: %w", fave.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if fave.TargetAccount.IsRemote() { | ||||
| 		// no need to notify | ||||
| 		// remote accounts. | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Ensure favee hasn't | ||||
| 	// muted the thread. | ||||
| 	muted, err := s.State.DB.IsThreadMutedByAccount( | ||||
| 		ctx, | ||||
| 		fave.Status.ThreadID, | ||||
| 		fave.TargetAccountID, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return false, gtserror.Newf("error checking status thread mute %s: %w", fave.StatusID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if muted { | ||||
| 		// Favee doesn't want | ||||
| 		// notifs for this thread. | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| // notifyAnnounce notifies the status boost target | ||||
| // account that their status has been boosted. | ||||
| func (s *Surface) notifyAnnounce( | ||||
| 	ctx context.Context, | ||||
| 	status *gtsmodel.Status, | ||||
| 	boost *gtsmodel.Status, | ||||
| ) error { | ||||
| 	notifyable, err := s.notifyableAnnounce(ctx, boost) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if !notifyable { | ||||
| 		// Nothing to do. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// notify status author | ||||
| 	// of boost by account. | ||||
| 	if err := s.Notify(ctx, | ||||
| 		gtsmodel.NotificationReblog, | ||||
| 		boost.BoostOfAccount, | ||||
| 		boost.Account, | ||||
| 		boost.ID, | ||||
| 	); err != nil { | ||||
| 		return gtserror.Newf("error notifying boost target %s: %w", boost.BoostOfAccountID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // notifyPendingAnnounce notifies the status boost | ||||
| // target account that their status has been boosted, | ||||
| // and that the boost requires approval. | ||||
| func (s *Surface) notifyPendingAnnounce( | ||||
| 	ctx context.Context, | ||||
| 	boost *gtsmodel.Status, | ||||
| ) error { | ||||
| 	notifyable, err := s.notifyableAnnounce(ctx, boost) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if !notifyable { | ||||
| 		// Nothing to do. | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// notify status author | ||||
| 	// of boost by account. | ||||
| 	if err := s.Notify(ctx, | ||||
| 		gtsmodel.NotificationPendingReblog, | ||||
| 		boost.BoostOfAccount, | ||||
| 		boost.Account, | ||||
| 		boost.ID, | ||||
| 	); err != nil { | ||||
| 		return gtserror.Newf("error notifying boost target %s: %w", boost.BoostOfAccountID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // notifyableAnnounce checks that the given | ||||
| // announce should be notified, taking account | ||||
| // of localness of receiving account, and mutes. | ||||
| func (s *Surface) notifyableAnnounce( | ||||
| 	ctx context.Context, | ||||
| 	status *gtsmodel.Status, | ||||
| ) (bool, error) { | ||||
| 	if status.BoostOfID == "" { | ||||
| 		// Not a boost, nothing to do. | ||||
| 		return nil | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	if status.BoostOfAccountID == status.AccountID { | ||||
| 		// Self-boost, nothing to do. | ||||
| 		return nil | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Beforehand, ensure the passed status is fully populated. | ||||
| 	if err := s.State.DB.PopulateStatus(ctx, status); err != nil { | ||||
| 		return gtserror.Newf("error populating status %s: %w", status.ID, err) | ||||
| 		return false, gtserror.Newf("error populating status %s: %w", status.ID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if status.BoostOfAccount.IsRemote() { | ||||
| 		// no need to notify | ||||
| 		// remote accounts. | ||||
| 		return nil | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Ensure boostee hasn't | ||||
|  | @ -264,27 +433,16 @@ func (s *Surface) notifyAnnounce( | |||
| 	) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return gtserror.Newf("error checking status thread mute %s: %w", status.BoostOfID, err) | ||||
| 		return false, gtserror.Newf("error checking status thread mute %s: %w", status.BoostOfID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	if muted { | ||||
| 		// Boostee doesn't want | ||||
| 		// notifs for this thread. | ||||
| 		return nil | ||||
| 		return false, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// notify status author | ||||
| 	// of boost by account. | ||||
| 	if err := s.Notify(ctx, | ||||
| 		gtsmodel.NotificationReblog, | ||||
| 		status.BoostOfAccount, | ||||
| 		status.Account, | ||||
| 		status.ID, | ||||
| 	); err != nil { | ||||
| 		return gtserror.Newf("error notifying status author %s: %w", status.BoostOfAccountID, err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| 	return true, nil | ||||
| } | ||||
| 
 | ||||
| func (s *Surface) notifyPollClose(ctx context.Context, status *gtsmodel.Status) error { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue