| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // 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/>. | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | package account | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-03-15 16:12:35 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-26 15:34:10 +02:00
										 |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/ap" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/db" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/gtscontext" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/gtserror" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/gtsmodel" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/log" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/messages" | 
					
						
							|  |  |  | 	"code.superseriousbusiness.org/gotosocial/internal/util" | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"codeberg.org/gruf/go-kv" | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	"github.com/google/uuid" | 
					
						
							|  |  |  | 	"golang.org/x/crypto/bcrypt" | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | const deleteSelectLimit = 100 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | // Delete deletes an account, and all of that account's statuses, media, follows, notifications, etc etc etc. | 
					
						
							|  |  |  | // The origin passed here should be either the ID of the account doing the delete (can be itself), or the ID of a domain block. | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // This delete function handles the case of both local and remote accounts, and processes side | 
					
						
							|  |  |  | // effects synchronously to not clog worker queues with potentially tens-of-thousands of requests. | 
					
						
							|  |  |  | func (p *Processor) Delete(ctx context.Context, account *gtsmodel.Account, origin string) error { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prepare a new log entry for account delete. | 
					
						
							|  |  |  | 	log := log.WithContext(ctx).WithFields(kv.Fields{ | 
					
						
							|  |  |  | 		{"uri", account.URI}, | 
					
						
							|  |  |  | 		{"origin", origin}, | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	}...) | 
					
						
							| 
									
										
										
										
											2022-11-20 14:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Log operation start / stop. | 
					
						
							|  |  |  | 	log.Info("start account delete") | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			log.Errorf("fatal error during account delete: %v", err) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			log.Info("finished account delete") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete statuses *before* anything else as for local | 
					
						
							|  |  |  | 	// accounts we need to federate out deletes, which relies | 
					
						
							|  |  |  | 	// on follows for addressing the appropriate accounts. | 
					
						
							|  |  |  | 	p.deleteAccountStatuses(ctx, &log, account) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Now delete relationships to / from account. | 
					
						
							|  |  |  | 	p.deleteAccountRelations(ctx, &log, account) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Now delete any notifications to / from account. | 
					
						
							|  |  |  | 	p.deleteAccountNotifications(ctx, &log, account) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Delete other peripheral objects ownable / | 
					
						
							|  |  |  | 	// manageable by any local / remote account. | 
					
						
							|  |  |  | 	p.deleteAccountPeripheral(ctx, &log, account) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 15:08:41 +01:00
										 |  |  | 	if account.IsLocal() { | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 		// We delete tokens, applications and clients for | 
					
						
							|  |  |  | 		// account as one of the last stages during deletion, | 
					
						
							|  |  |  | 		// as other database models rely on these. | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		if err = p.deleteUserAndTokensForAccount(ctx, &log, account); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							| 
									
										
										
										
											2023-08-10 15:08:41 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	// To prevent the account being created again, | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// (which would cause horrible federation shenanigans), | 
					
						
							|  |  |  | 	// the account will be stubbed out to an unusable state | 
					
						
							|  |  |  | 	// with no identifying info remaining, but NOT deleted. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	columns := stubbifyAccount(account, origin) | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	if err = p.state.DB.UpdateAccount(ctx, account, columns...); err != nil { | 
					
						
							|  |  |  | 		return gtserror.Newf("error stubbing out account: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | func (p *Processor) deleteUserAndTokensForAccount( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	log *log.Entry, | 
					
						
							|  |  |  | 	account *gtsmodel.Account, | 
					
						
							|  |  |  | ) error { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Fetch the associated user for account, on fail return | 
					
						
							|  |  |  | 	// early as all other parts of this func rely on this user. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	user, err := p.state.DB.GetUserByAccountID(ctx, account.ID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		return gtserror.Newf("error getting account user: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Get list of applications managed by deleting user. | 
					
						
							|  |  |  | 	apps, err := p.state.DB.GetApplicationsManagedByUserID(ctx, | 
					
						
							|  |  |  | 		user.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2025-03-17 15:06:17 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting user applications: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-17 15:06:17 +01:00
										 |  |  | 	// Delete each app and any tokens it had created | 
					
						
							|  |  |  | 	// (not necessarily owned by deleted account). | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	for _, app := range apps { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteTokensByClientID(ctx, app.ClientID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting application token: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		if err := p.state.DB.DeleteApplicationByID(ctx, app.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting user application: %v", err) | 
					
						
							| 
									
										
										
										
											2025-03-17 15:06:17 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get any remaining access tokens owned by user. | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	tokens, err := p.state.DB.GetAccessTokens(ctx, | 
					
						
							|  |  |  | 		user.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2025-03-17 15:06:17 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting user access tokens: %v", err) | 
					
						
							| 
									
										
										
										
											2025-03-17 15:06:17 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete user access tokens. | 
					
						
							|  |  |  | 	for _, token := range tokens { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteTokenByID(ctx, token.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting user access token: %v", err) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete any web push subscriptions created by this local user account. | 
					
						
							| 
									
										
										
										
											2025-01-23 16:47:30 -08:00
										 |  |  | 	if err := p.state.DB.DeleteWebPushSubscriptionsByAccountID(ctx, account.ID); err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error deleting account web push subscriptions: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// To prevent the user being created again, | 
					
						
							|  |  |  | 	// the user will be stubbed out to an unusable state | 
					
						
							|  |  |  | 	// with no identifying info remaining, but NOT deleted. | 
					
						
							|  |  |  | 	columns := stubbifyUser(user) | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	if err := p.state.DB.UpdateUser(ctx, user, columns...); err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		return gtserror.Newf("error stubbing out user: %w", err) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | func (p *Processor) deleteAccountRelations( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	log *log.Entry, | 
					
						
							|  |  |  | 	account *gtsmodel.Account, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	// Get a list of the follows targeting this account. | 
					
						
							|  |  |  | 	followedBy, err := p.state.DB.GetAccountFollowers(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting account followed-bys: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these follows from database. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	for _, follow := range followedBy { | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | 		if err := p.state.DB.DeleteFollowByID(ctx, follow.ID); err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 			log.Errorf("error deleting account followed-by %s: %v", follow.URI, err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Get a list of the follow requests targeting this account. | 
					
						
							|  |  |  | 	followRequestedBy, err := p.state.DB.GetAccountFollowRequests(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting account follow-requested-bys: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these follow requests from database. | 
					
						
							|  |  |  | 	for _, followReq := range followRequestedBy { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteFollowRequestByID(ctx, followReq.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting account follow-requested-by %s: %v", followReq.URI, err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Get a list of the blocks targeting this account. | 
					
						
							|  |  |  | 	blockedBy, err := p.state.DB.GetAccountBlockedBy(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 		log.Errorf("error getting account blocked-bys: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these blocks from database. | 
					
						
							|  |  |  | 	for _, block := range blockedBy { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteBlockByID(ctx, block.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting account blocked-by %s: %v", block.URI, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Get the follows originating from this account. | 
					
						
							|  |  |  | 	following, err := p.state.DB.GetAccountFollows(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting account follows: %v", err) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these follows from database. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	for _, follow := range following { | 
					
						
							| 
									
										
											  
											
												[performance] refactoring + add fave / follow / request / visibility caching (#1607)
* refactor visibility checking, add caching for visibility
* invalidate visibility cache items on account / status deletes
* fix requester ID passed to visibility cache nil ptr
* de-interface caches, fix home / public timeline caching + visibility
* finish adding code comments for visibility filter
* fix angry goconst linter warnings
* actually finish adding filter visibility code comments for timeline functions
* move home timeline status author check to after visibility
* remove now-unused code
* add more code comments
* add TODO code comment, update printed cache start names
* update printed cache names on stop
* start adding separate follow(request) delete db functions, add specific visibility cache tests
* add relationship type caching
* fix getting local account follows / followed-bys, other small codebase improvements
* simplify invalidation using cache hooks, add more GetAccountBy___() functions
* fix boosting to return 404 if not boostable but no error (to not leak status ID)
* remove dead code
* improved placement of cache invalidation
* update license headers
* add example follow, follow-request config entries
* add example visibility cache configuration to config file
* use specific PutFollowRequest() instead of just Put()
* add tests for all GetAccountBy()
* add GetBlockBy() tests
* update block to check primitive fields
* update and finish adding Get{Account,Block,Follow,FollowRequest}By() tests
* fix copy-pasted code
* update envparsing test
* whitespace
* fix bun struct tag
* add license header to gtscontext
* fix old license header
* improved error creation to not use fmt.Errorf() when not needed
* fix various rebase conflicts, fix account test
* remove commented-out code, fix-up mention caching
* fix mention select bun statement
* ensure mention target account populated, pass in context to customrenderer logging
* remove more uncommented code, fix typeutil test
* add statusfave database model caching
* add status fave cache configuration
* add status fave cache example config
* woops, catch missed error. nice catch linter!
* add back testrig panic on nil db
* update example configuration to match defaults, slight tweak to cache configuration defaults
* update envparsing test with new defaults
* fetch followingget to use the follow target account
* use accounnt.IsLocal() instead of empty domain check
* use constants for the cache visibility type check
* use bun.In() for notification type restriction in db query
* include replies when fetching PublicTimeline() (to account for single-author threads in Visibility{}.StatusPublicTimelineable())
* use bun query building for nested select statements to ensure working with postgres
* update public timeline future status checks to match visibility filter
* same as previous, for home timeline
* update public timeline tests to dynamically check for appropriate statuses
* migrate accounts to allow unique constraint on public_key
* provide minimal account with publicKey
---------
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
											
										 
											2023-03-28 14:03:14 +01:00
										 |  |  | 		if err := p.state.DB.DeleteFollowByID(ctx, follow.ID); err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 			log.Errorf("error deleting account followed %s: %v", follow.URI, err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Get a list of the follow requests originating from this account. | 
					
						
							|  |  |  | 	followRequesting, err := p.state.DB.GetAccountFollowRequesting(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error getting account follow-requests: %v", err) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these follow requests from database. | 
					
						
							|  |  |  | 	for _, followReq := range followRequesting { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteFollowRequestByID(ctx, followReq.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting account follow-request %s: %v", followReq.URI, err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Get the blocks originating from this account. | 
					
						
							|  |  |  | 	blocking, err := p.state.DB.GetAccountBlocking(ctx, | 
					
						
							|  |  |  | 		account.ID, | 
					
						
							|  |  |  | 		nil, // i.e. all | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 		log.Errorf("error getting account blocks: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete these blocks from database. | 
					
						
							|  |  |  | 	for _, block := range blocking { | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteBlockByID(ctx, block.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting account block %s: %v", block.URI, err) | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-11-20 14:57:19 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete all mutes targetting / originating from account. | 
					
						
							|  |  |  | 	if err := p.state.DB.DeleteAccountMutes(ctx, account.ID); // nocollapse | 
					
						
							|  |  |  | 	err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 		log.Errorf("error deleting mutes to / from account: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	if account.IsLocal() { | 
					
						
							|  |  |  | 		// Process side-effects for deleting | 
					
						
							|  |  |  | 		// of account follows from local user. | 
					
						
							|  |  |  | 		for _, follow := range following { | 
					
						
							|  |  |  | 			p.processSideEffect(ctx, log, | 
					
						
							|  |  |  | 				ap.ActivityUndo, | 
					
						
							|  |  |  | 				ap.ActivityFollow, | 
					
						
							|  |  |  | 				follow, | 
					
						
							|  |  |  | 				account, | 
					
						
							|  |  |  | 				follow.TargetAccount, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Process side-effects for deleting of account follow requests | 
					
						
							|  |  |  | 		// from local user. Though handled as though UNDO of a follow. | 
					
						
							|  |  |  | 		for _, followReq := range followRequesting { | 
					
						
							|  |  |  | 			p.processSideEffect(ctx, log, | 
					
						
							|  |  |  | 				ap.ActivityUndo, | 
					
						
							|  |  |  | 				ap.ActivityFollow, | 
					
						
							|  |  |  | 				>smodel.Follow{ | 
					
						
							|  |  |  | 					ID:              followReq.ID, | 
					
						
							|  |  |  | 					URI:             followReq.URI, | 
					
						
							|  |  |  | 					AccountID:       followReq.AccountID, | 
					
						
							|  |  |  | 					Account:         followReq.Account, | 
					
						
							|  |  |  | 					TargetAccountID: followReq.TargetAccountID, | 
					
						
							|  |  |  | 					TargetAccount:   followReq.TargetAccount, | 
					
						
							|  |  |  | 					ShowReblogs:     new(bool), | 
					
						
							|  |  |  | 					Notify:          new(bool), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				account, | 
					
						
							|  |  |  | 				followReq.TargetAccount, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Process side-effects for deleting | 
					
						
							|  |  |  | 		// of account blocks from local user. | 
					
						
							|  |  |  | 		for _, block := range blocking { | 
					
						
							|  |  |  | 			p.processSideEffect(ctx, log, | 
					
						
							|  |  |  | 				ap.ActivityUndo, | 
					
						
							|  |  |  | 				ap.ActivityBlock, | 
					
						
							|  |  |  | 				block, | 
					
						
							|  |  |  | 				account, | 
					
						
							|  |  |  | 				block.TargetAccount, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | func (p *Processor) deleteAccountStatuses( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	log *log.Entry, | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 	account *gtsmodel.Account, | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | ) { | 
					
						
							|  |  |  | 	var maxID string | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Page through deleting account's statuses. | 
					
						
							|  |  |  | 		statuses, err := p.state.DB.GetAccountStatuses( | 
					
						
							|  |  |  | 			gtscontext.SetBarebones(ctx), | 
					
						
							| 
									
										
										
										
											2023-08-10 15:08:41 +01:00
										 |  |  | 			account.ID, | 
					
						
							|  |  |  | 			deleteSelectLimit, | 
					
						
							|  |  |  | 			false, | 
					
						
							|  |  |  | 			false, | 
					
						
							|  |  |  | 			maxID, | 
					
						
							|  |  |  | 			"", | 
					
						
							|  |  |  | 			false, | 
					
						
							|  |  |  | 			false, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 			log.Errorf("error getting account statuses: %v", err) | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-08 10:33:03 +00:00
										 |  |  | 		if len(statuses) == 0 { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 			// reached | 
					
						
							|  |  |  | 			// the end. | 
					
						
							|  |  |  | 			break | 
					
						
							| 
									
										
										
										
											2023-01-08 10:33:03 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		// Update next maxID from last status. | 
					
						
							|  |  |  | 		maxID = statuses[len(statuses)-1].ID | 
					
						
							| 
									
										
										
										
											2022-07-10 16:18:21 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		for _, status := range statuses { | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 			// Ensure account is set. | 
					
						
							|  |  |  | 			status.Account = account | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 			// Look for any boosts of this status in DB. | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 			boosts, err := p.state.DB.GetStatusBoosts( | 
					
						
							|  |  |  | 				gtscontext.SetBarebones(ctx), | 
					
						
							|  |  |  | 				status.ID, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2022-11-20 14:57:19 +00:00
										 |  |  | 			if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 				log.Errorf("error getting status boosts for %s: %v", status.URI, err) | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2022-11-20 14:57:19 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 			// Prepare to Undo each boost. | 
					
						
							| 
									
										
										
										
											2022-11-20 14:57:19 +00:00
										 |  |  | 			for _, boost := range boosts { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// Fetch the owning account of this boost. | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 				boost.Account, err = p.state.DB.GetAccountByID( | 
					
						
							|  |  |  | 					gtscontext.SetBarebones(ctx), | 
					
						
							|  |  |  | 					boost.AccountID, | 
					
						
							|  |  |  | 				) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 					log.Errorf("error getting owner %s of status boost %s: %v", | 
					
						
							|  |  |  | 						boost.AccountURI, boost.URI, err) | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 					continue | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 				// Process boost undo event. | 
					
						
							|  |  |  | 				p.processSideEffect(ctx, log, | 
					
						
							|  |  |  | 					ap.ActivityUndo, | 
					
						
							|  |  |  | 					ap.ActivityAnnounce, | 
					
						
							|  |  |  | 					boost, | 
					
						
							|  |  |  | 					account, | 
					
						
							|  |  |  | 					account, | 
					
						
							|  |  |  | 				) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 			// Process status delete event. | 
					
						
							|  |  |  | 			p.processSideEffect(ctx, log, | 
					
						
							|  |  |  | 				ap.ActivityDelete, | 
					
						
							|  |  |  | 				ap.ObjectNote, | 
					
						
							|  |  |  | 				status, | 
					
						
							|  |  |  | 				account, | 
					
						
							|  |  |  | 				account, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | func (p *Processor) deleteAccountNotifications( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	log *log.Entry, | 
					
						
							|  |  |  | 	account *gtsmodel.Account, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	if account.IsLocal() { | 
					
						
							|  |  |  | 		// Delete all types of notifications targeting this local account. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteNotifications(ctx, nil, account.ID, ""); // nocollapse | 
					
						
							|  |  |  | 		err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			log.Errorf("error deleting notifications targeting account: %v", err) | 
					
						
							| 
									
										
										
										
											2023-11-14 15:57:25 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete all types of notifications originating from this account. | 
					
						
							|  |  |  | 	if err := p.state.DB.DeleteNotifications(ctx, nil, "", account.ID); // nocollapse | 
					
						
							|  |  |  | 	err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 		log.Errorf("error deleting notifications originating from account: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-09-30 10:56:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | func (p *Processor) deleteAccountPeripheral( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	log *log.Entry, | 
					
						
							|  |  |  | 	account *gtsmodel.Account, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	if account.IsLocal() { | 
					
						
							|  |  |  | 		// Delete all bookmarks owned by given account, only for local. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteStatusBookmarks(ctx, account.ID, ""); // nocollapse | 
					
						
							|  |  |  | 		err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			log.Errorf("error deleting bookmarks by account: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Delete all faves owned by given account, only for local. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteStatusFaves(ctx, account.ID, ""); // nocollapse | 
					
						
							|  |  |  | 		err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			log.Errorf("error deleting faves by account: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Delete all conversations owned by given account, only for local. | 
					
						
							|  |  |  | 		// | 
					
						
							|  |  |  | 		// *Participated* conversations will be retained, leaving up to *their* owners. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteConversationsByOwnerAccountID(ctx, account.ID); // nocollapse | 
					
						
							|  |  |  | 		err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			log.Errorf("error deleting conversations by account: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Delete all followed tags owned by given account, only for local. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteFollowedTagsByAccountID(ctx, account.ID); // nocollapse | 
					
						
							|  |  |  | 		err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			log.Errorf("error deleting followed tags by account: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// Delete stats model stored for given account, only for local. | 
					
						
							|  |  |  | 		if err := p.state.DB.DeleteAccountStats(ctx, account.ID); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error deleting stats for account: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete all bookmarks targeting given account, local and remote. | 
					
						
							|  |  |  | 	if err := p.state.DB.DeleteStatusBookmarks(ctx, "", account.ID); // nocollapse | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error deleting bookmarks targeting account: %v", err) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete all faves targeting given account, local and remote. | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	if err := p.state.DB.DeleteStatusFaves(ctx, "", account.ID); // nocollapse | 
					
						
							|  |  |  | 	err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error deleting faves targeting account: %v", err) | 
					
						
							| 
									
										
										
										
											2024-07-23 12:44:31 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	// Delete all poll votes owned by given account, local and remote. | 
					
						
							| 
									
										
										
										
											2023-11-08 14:32:17 +00:00
										 |  |  | 	if err := p.state.DB.DeletePollVotesByAccountID(ctx, account.ID); // nocollapse | 
					
						
							|  |  |  | 	err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		log.Errorf("error deleting poll votes by account: %v", err) | 
					
						
							| 
									
										
										
										
											2024-07-29 11:26:31 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2024-07-29 11:26:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | // processSideEffect will process the given side effect details, | 
					
						
							|  |  |  | // with appropriate worker depending on if origin is local / remote. | 
					
						
							|  |  |  | func (p *Processor) processSideEffect( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	log *log.Entry, | 
					
						
							|  |  |  | 	activityType string, | 
					
						
							|  |  |  | 	objectType string, | 
					
						
							|  |  |  | 	gtsModel any, | 
					
						
							|  |  |  | 	origin *gtsmodel.Account, | 
					
						
							|  |  |  | 	target *gtsmodel.Account, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	if origin.IsLocal() { | 
					
						
							|  |  |  | 		// Process side-effect through our client API as this is a local account. | 
					
						
							|  |  |  | 		if err := p.state.Workers.Client.Process(ctx, &messages.FromClientAPI{ | 
					
						
							|  |  |  | 			APActivityType: activityType, | 
					
						
							|  |  |  | 			APObjectType:   objectType, | 
					
						
							|  |  |  | 			GTSModel:       gtsModel, | 
					
						
							|  |  |  | 			Origin:         origin, | 
					
						
							|  |  |  | 			Target:         target, | 
					
						
							|  |  |  | 		}); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error processing %s of %s during local account %s delete: %v", activityType, objectType, origin.ID, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Process side-effect through our fedi API as this is a remote account. | 
					
						
							|  |  |  | 		if err := p.state.Workers.Federator.Process(ctx, &messages.FromFediAPI{ | 
					
						
							|  |  |  | 			APActivityType: activityType, | 
					
						
							|  |  |  | 			APObjectType:   objectType, | 
					
						
							|  |  |  | 			GTSModel:       gtsModel, | 
					
						
							|  |  |  | 			Requesting:     origin, | 
					
						
							|  |  |  | 			Receiving:      target, | 
					
						
							|  |  |  | 		}); err != nil { | 
					
						
							|  |  |  | 			log.Errorf("error processing %s of %s during local account %s delete: %v", activityType, objectType, origin.ID, err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-04-16 13:10:13 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // stubbifyAccount renders the given account as a stub, | 
					
						
							|  |  |  | // removing most information from it and marking it as | 
					
						
							|  |  |  | // suspended. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The origin parameter refers to the origin of the | 
					
						
							|  |  |  | // suspension action; should be an account ID or domain | 
					
						
							|  |  |  | // block ID. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For caller's convenience, this function returns the db | 
					
						
							|  |  |  | // names of all columns that are updated by it. | 
					
						
							|  |  |  | func stubbifyAccount(account *gtsmodel.Account, origin string) []string { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2023-08-07 19:38:11 +02:00
										 |  |  | 		now   = time.Now() | 
					
						
							|  |  |  | 		never = time.Time{} | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	account.FetchedAt = never | 
					
						
							| 
									
										
										
										
											2021-07-05 13:23:03 +02:00
										 |  |  | 	account.AvatarMediaAttachmentID = "" | 
					
						
							|  |  |  | 	account.AvatarRemoteURL = "" | 
					
						
							|  |  |  | 	account.HeaderMediaAttachmentID = "" | 
					
						
							|  |  |  | 	account.HeaderRemoteURL = "" | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	account.DisplayName = "" | 
					
						
							|  |  |  | 	account.EmojiIDs = nil | 
					
						
							|  |  |  | 	account.Emojis = nil | 
					
						
							|  |  |  | 	account.Fields = nil | 
					
						
							|  |  |  | 	account.Note = "" | 
					
						
							|  |  |  | 	account.NoteRaw = "" | 
					
						
							| 
									
										
										
										
											2025-04-06 14:39:40 +02:00
										 |  |  | 	account.MemorializedAt = never | 
					
						
							| 
									
										
										
										
											2024-01-16 17:22:44 +01:00
										 |  |  | 	account.AlsoKnownAsURIs = nil | 
					
						
							|  |  |  | 	account.MovedToURI = "" | 
					
						
							| 
									
										
										
										
											2023-08-07 19:38:11 +02:00
										 |  |  | 	account.Discoverable = util.Ptr(false) | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 	account.SuspendedAt = now | 
					
						
							| 
									
										
										
										
											2021-07-06 13:29:11 +02:00
										 |  |  | 	account.SuspensionOrigin = origin | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return []string{ | 
					
						
							|  |  |  | 		"fetched_at", | 
					
						
							|  |  |  | 		"avatar_media_attachment_id", | 
					
						
							|  |  |  | 		"avatar_remote_url", | 
					
						
							|  |  |  | 		"header_media_attachment_id", | 
					
						
							|  |  |  | 		"header_remote_url", | 
					
						
							|  |  |  | 		"display_name", | 
					
						
							|  |  |  | 		"emojis", | 
					
						
							|  |  |  | 		"fields", | 
					
						
							|  |  |  | 		"note", | 
					
						
							|  |  |  | 		"note_raw", | 
					
						
							| 
									
										
										
										
											2025-04-06 14:39:40 +02:00
										 |  |  | 		"memorialized_at", | 
					
						
							| 
									
										
										
										
											2024-01-16 17:22:44 +01:00
										 |  |  | 		"also_known_as_uris", | 
					
						
							|  |  |  | 		"moved_to_uri", | 
					
						
							| 
									
										
										
										
											2023-03-20 19:10:08 +01:00
										 |  |  | 		"discoverable", | 
					
						
							|  |  |  | 		"suspended_at", | 
					
						
							|  |  |  | 		"suspension_origin", | 
					
						
							| 
									
										
										
										
											2022-03-15 16:12:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | // stubbifyUser renders the given user as a stub, | 
					
						
							|  |  |  | // removing sensitive information like IP addresses | 
					
						
							|  |  |  | // and sign-in times, but keeping email addresses to | 
					
						
							|  |  |  | // prevent the same email address from creating another | 
					
						
							|  |  |  | // account on this instance. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // `encrypted_password` is set to the bcrypt hash of a | 
					
						
							|  |  |  | // random uuid, so if the action is reversed, the user | 
					
						
							|  |  |  | // will have to reset their password via email. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For caller's convenience, this function returns the db | 
					
						
							|  |  |  | // names of all columns that are updated by it. | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | func stubbifyUser(user *gtsmodel.User) []string { | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	uuid, err := uuid.New().MarshalBinary() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// this should never happen, | 
					
						
							|  |  |  | 		// it indicates /dev/random | 
					
						
							|  |  |  | 		// is misbehaving. | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dummyPassword, err := bcrypt.GenerateFromPassword(uuid, bcrypt.DefaultCost) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 		// this should never happen, | 
					
						
							|  |  |  | 		// it indicates /dev/random | 
					
						
							|  |  |  | 		// is misbehaving. | 
					
						
							|  |  |  | 		panic(err) | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-31 11:25:29 +01:00
										 |  |  | 	never := time.Time{} | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	user.EncryptedPassword = string(dummyPassword) | 
					
						
							|  |  |  | 	user.SignUpIP = net.IPv4zero | 
					
						
							|  |  |  | 	user.Locale = "" | 
					
						
							|  |  |  | 	user.CreatedByApplicationID = "" | 
					
						
							|  |  |  | 	user.LastEmailedAt = never | 
					
						
							|  |  |  | 	user.ConfirmationToken = "" | 
					
						
							|  |  |  | 	user.ConfirmationSentAt = never | 
					
						
							|  |  |  | 	user.ResetPasswordToken = "" | 
					
						
							|  |  |  | 	user.ResetPasswordSentAt = never | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return []string{ | 
					
						
							|  |  |  | 		"encrypted_password", | 
					
						
							|  |  |  | 		"sign_up_ip", | 
					
						
							|  |  |  | 		"locale", | 
					
						
							|  |  |  | 		"created_by_application_id", | 
					
						
							|  |  |  | 		"last_emailed_at", | 
					
						
							|  |  |  | 		"confirmation_token", | 
					
						
							|  |  |  | 		"confirmation_sent_at", | 
					
						
							|  |  |  | 		"reset_password_token", | 
					
						
							|  |  |  | 		"reset_password_sent_at", | 
					
						
							| 
									
										
										
										
											2025-06-11 11:38:10 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-03-31 15:01:29 +02:00
										 |  |  | } |