| 
									
										
										
										
											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-05-29 19:39:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-30 13:12:00 +02:00
										 |  |  | package processing | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-08-25 15:34:33 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-05-29 20:35:03 +02:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"codeberg.org/gruf/go-kv" | 
					
						
							| 
									
										
										
										
											2023-04-06 13:19:55 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/ap" | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/config" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/db" | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing" | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext" | 
					
						
							| 
									
										
										
										
											2021-06-13 18:42:28 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/oauth" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | // Implementation note: in this function, we tend to log errors | 
					
						
							|  |  |  | // at debug level rather than return them. This is because the | 
					
						
							|  |  |  | // search has a sort of fallthrough logic: if we can't get a result | 
					
						
							|  |  |  | // with x search, we should try with y search rather than returning. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // If we get to the end and still haven't found anything, even then | 
					
						
							|  |  |  | // we shouldn't return an error, just return an empty search result. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The only exception to this is when we get a malformed query, in | 
					
						
							|  |  |  | // which case we return a bad request error so the user knows they | 
					
						
							|  |  |  | // did something funky. | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) SearchGet(ctx context.Context, authed *oauth.Auth, search *apimodel.SearchQuery) (*apimodel.SearchResult, gtserror.WithCode) { | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	// tidy up the query and make sure it wasn't just spaces | 
					
						
							|  |  |  | 	query := strings.TrimSpace(search.Query) | 
					
						
							|  |  |  | 	if query == "" { | 
					
						
							|  |  |  | 		err := errors.New("search query was empty string after trimming space") | 
					
						
							|  |  |  | 		return nil, gtserror.NewErrorBadRequest(err, err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-17 12:02:29 +01:00
										 |  |  | 	l := log.WithContext(ctx). | 
					
						
							|  |  |  | 		WithFields(kv.Fields{{"query", query}}...) | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	searchResult := &apimodel.SearchResult{ | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 		Accounts: []apimodel.Account{}, | 
					
						
							|  |  |  | 		Statuses: []apimodel.Status{}, | 
					
						
							|  |  |  | 		Hashtags: []apimodel.Tag{}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-31 03:57:50 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// currently the search will only ever return one result, | 
					
						
							|  |  |  | 	// so return nothing if the offset is greater than 0 | 
					
						
							|  |  |  | 	if search.Offset > 0 { | 
					
						
							|  |  |  | 		return searchResult, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	foundAccounts := []*gtsmodel.Account{} | 
					
						
							|  |  |  | 	foundStatuses := []*gtsmodel.Status{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 20:35:03 +02:00
										 |  |  | 	var foundOne bool | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* | 
					
						
							|  |  |  | 		SEARCH BY MENTION | 
					
						
							| 
									
										
										
										
											2022-08-20 22:47:19 +02:00
										 |  |  | 		check if the query is something like @whatever_username@example.org -- this means it's likely a remote account | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	*/ | 
					
						
							|  |  |  | 	maybeNamestring := query | 
					
						
							|  |  |  | 	if maybeNamestring[0] != '@' { | 
					
						
							|  |  |  | 		maybeNamestring = "@" + maybeNamestring | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if username, domain, err := util.ExtractNamestringParts(maybeNamestring); err == nil { | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		l.Trace("search term is a mention, looking it up...") | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 		blocked, err := p.state.DB.IsDomainBlocked(ctx, domain) | 
					
						
							| 
									
										
										
										
											2023-02-14 11:55:02 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking domain block: %w", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if blocked { | 
					
						
							|  |  |  | 			l.Debug("domain is blocked") | 
					
						
							|  |  |  | 			return searchResult, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		foundAccount, err := p.searchAccountByUsernameDomain(ctx, authed, username, domain, search.Resolve) | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			var errNotRetrievable *dereferencing.ErrNotRetrievable | 
					
						
							|  |  |  | 			if !errors.As(err, &errNotRetrievable) { | 
					
						
							|  |  |  | 				// return a proper error only if it wasn't just not retrievable | 
					
						
							|  |  |  | 				return nil, gtserror.NewErrorInternalError(fmt.Errorf("error looking up account: %w", err)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return searchResult, nil | 
					
						
							| 
									
										
										
										
											2021-05-29 20:35:03 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		foundAccounts = append(foundAccounts, foundAccount) | 
					
						
							|  |  |  | 		foundOne = true | 
					
						
							|  |  |  | 		l.Trace("got an account by searching by mention") | 
					
						
							| 
									
										
										
										
											2021-05-29 20:35:03 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 		SEARCH BY URI | 
					
						
							|  |  |  | 		check if the query is a URI with a recognizable scheme and dereference it | 
					
						
							|  |  |  | 	*/ | 
					
						
							| 
									
										
										
										
											2021-10-17 13:19:49 +01:00
										 |  |  | 	if !foundOne { | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		if uri, err := url.Parse(query); err == nil { | 
					
						
							|  |  |  | 			if uri.Scheme == "https" || uri.Scheme == "http" { | 
					
						
							|  |  |  | 				l.Trace("search term is a uri, looking it up...") | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 				blocked, err := p.state.DB.IsURIBlocked(ctx, uri) | 
					
						
							| 
									
										
										
										
											2023-02-14 11:55:02 +01:00
										 |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return nil, gtserror.NewErrorInternalError(fmt.Errorf("error checking domain block: %w", err)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if blocked { | 
					
						
							|  |  |  | 					l.Debug("domain is blocked") | 
					
						
							|  |  |  | 					return searchResult, nil | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 				// check if it's a status... | 
					
						
							|  |  |  | 				foundStatus, err := p.searchStatusByURI(ctx, authed, uri) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							| 
									
										
										
										
											2023-04-06 13:19:55 +02:00
										 |  |  | 					// Check for semi-expected error types. | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 					var ( | 
					
						
							|  |  |  | 						errNotRetrievable *dereferencing.ErrNotRetrievable | 
					
						
							| 
									
										
										
										
											2023-04-06 13:19:55 +02:00
										 |  |  | 						errWrongType      *ap.ErrWrongType | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 					) | 
					
						
							|  |  |  | 					if !errors.As(err, &errNotRetrievable) && !errors.As(err, &errWrongType) { | 
					
						
							|  |  |  | 						return nil, gtserror.NewErrorInternalError(fmt.Errorf("error looking up status: %w", err)) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					foundStatuses = append(foundStatuses, foundStatus) | 
					
						
							|  |  |  | 					foundOne = true | 
					
						
							|  |  |  | 					l.Trace("got a status by searching by URI") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// ... or an account | 
					
						
							|  |  |  | 				if !foundOne { | 
					
						
							|  |  |  | 					foundAccount, err := p.searchAccountByURI(ctx, authed, uri, search.Resolve) | 
					
						
							|  |  |  | 					if err != nil { | 
					
						
							| 
									
										
										
										
											2023-04-06 13:19:55 +02:00
										 |  |  | 						// Check for semi-expected error types. | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 						var ( | 
					
						
							|  |  |  | 							errNotRetrievable *dereferencing.ErrNotRetrievable | 
					
						
							| 
									
										
										
										
											2023-04-06 13:19:55 +02:00
										 |  |  | 							errWrongType      *ap.ErrWrongType | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 						) | 
					
						
							|  |  |  | 						if !errors.As(err, &errNotRetrievable) && !errors.As(err, &errWrongType) { | 
					
						
							|  |  |  | 							return nil, gtserror.NewErrorInternalError(fmt.Errorf("error looking up account: %w", err)) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						foundAccounts = append(foundAccounts, foundAccount) | 
					
						
							|  |  |  | 						foundOne = true | 
					
						
							|  |  |  | 						l.Trace("got an account by searching by URI") | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-10-17 13:19:49 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 	if !foundOne { | 
					
						
							|  |  |  | 		// we got nothing, we can return early | 
					
						
							|  |  |  | 		l.Trace("found nothing, returning") | 
					
						
							|  |  |  | 		return searchResult, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	/* | 
					
						
							|  |  |  | 		FROM HERE ON we have our search results, it's just a matter of filtering them according to what this user is allowed to see, | 
					
						
							|  |  |  | 		and then converting them into our frontend format. | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 	for _, foundAccount := range foundAccounts { | 
					
						
							|  |  |  | 		// make sure there's no block in either direction between the account and the requester | 
					
						
							| 
									
										
											  
											
												[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
										 |  |  | 		blocked, err := p.state.DB.IsEitherBlocked(ctx, authed.Account.ID, foundAccount.ID) | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("SearchGet: error checking block between %s and %s: %s", authed.Account.ID, foundAccount.ID, err) | 
					
						
							|  |  |  | 			return nil, gtserror.NewErrorInternalError(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if blocked { | 
					
						
							|  |  |  | 			l.Tracef("block exists between %s and %s, skipping this result", authed.Account.ID, foundAccount.ID) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		apiAcct, err := p.tc.AccountToAPIAccountPublic(ctx, foundAccount) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("SearchGet: error converting account %s to api account: %s", foundAccount.ID, err) | 
					
						
							|  |  |  | 			return nil, gtserror.NewErrorInternalError(err) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		searchResult.Accounts = append(searchResult.Accounts, *apiAcct) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, foundStatus := range foundStatuses { | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		// make sure each found status is visible to the requester | 
					
						
							| 
									
										
											  
											
												[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
										 |  |  | 		visible, err := p.filter.StatusVisible(ctx, authed.Account, foundStatus) | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("SearchGet: error checking visibility of status %s for account %s: %s", foundStatus.ID, authed.Account.ID, err) | 
					
						
							|  |  |  | 			return nil, gtserror.NewErrorInternalError(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if !visible { | 
					
						
							|  |  |  | 			l.Tracef("status %s is not visible to account %s, skipping this result", foundStatus.ID, authed.Account.ID) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-04 15:24:19 +02:00
										 |  |  | 		apiStatus, err := p.tc.StatusToAPIStatus(ctx, foundStatus, authed.Account) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 			err = fmt.Errorf("SearchGet: error converting status %s to api status: %s", foundStatus.ID, err) | 
					
						
							|  |  |  | 			return nil, gtserror.NewErrorInternalError(err) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 		searchResult.Statuses = append(searchResult.Statuses, *apiStatus) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:01:34 +02:00
										 |  |  | 	return searchResult, nil | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) searchStatusByURI(ctx context.Context, authed *oauth.Auth, uri *url.URL) (*gtsmodel.Status, error) { | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 	status, statusable, err := p.federator.GetStatus(gtscontext.SetFastFail(ctx), authed.Account.Username, uri, true, true) | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 	if !*status.Local && statusable != nil { | 
					
						
							| 
									
										
										
										
											2022-09-25 12:09:41 +01:00
										 |  |  | 		// Attempt to dereference the status thread while we are here | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 		p.federator.DereferenceThread(gtscontext.SetFastFail(ctx), authed.Account.Username, uri, status, statusable) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-09-25 12:09:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-29 10:24:55 +01:00
										 |  |  | 	return status, nil | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) searchAccountByURI(ctx context.Context, authed *oauth.Auth, uri *url.URL, resolve bool) (*gtsmodel.Account, error) { | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 	if !resolve { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			account *gtsmodel.Account | 
					
						
							|  |  |  | 			err     error | 
					
						
							|  |  |  | 			uriStr  = uri.String() | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Search the database for existing account with ID URI. | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 		account, err = p.state.DB.GetAccountByURI(ctx, uriStr) | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		if err != nil && !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("searchAccountByURI: error checking database for account %s: %w", uriStr, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if account == nil { | 
					
						
							|  |  |  | 			// Else, search the database for existing by ID URL. | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 			account, err = p.state.DB.GetAccountByURL(ctx, uriStr) | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				if !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 					return nil, fmt.Errorf("searchAccountByURI: error checking database for account %s: %w", uriStr, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return nil, dereferencing.NewErrNotRetrievable(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return account, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.federator.GetAccountByURI( | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 		gtscontext.SetFastFail(ctx), | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		authed.Account.Username, | 
					
						
							|  |  |  | 		uri, false, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-22 16:05:26 +01:00
										 |  |  | func (p *Processor) searchAccountByUsernameDomain(ctx context.Context, authed *oauth.Auth, username string, domain string, resolve bool) (*gtsmodel.Account, error) { | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 	if !resolve { | 
					
						
							|  |  |  | 		if domain == config.GetHost() || domain == config.GetAccountDomain() { | 
					
						
							|  |  |  | 			// We do local lookups using an empty domain, | 
					
						
							|  |  |  | 			// else it will fail the db search below. | 
					
						
							|  |  |  | 			domain = "" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Search the database for existing account with USERNAME@DOMAIN | 
					
						
							| 
									
										
										
										
											2023-03-01 18:26:53 +00:00
										 |  |  | 		account, err := p.state.DB.GetAccountByUsernameDomain(ctx, username, domain) | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if !errors.Is(err, db.ErrNoEntries) { | 
					
						
							|  |  |  | 				return nil, fmt.Errorf("searchAccountByUsernameDomain: error checking database for account %s@%s: %w", username, domain, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nil, dereferencing.NewErrNotRetrievable(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return account, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p.federator.GetAccountByUsernameDomain( | 
					
						
							| 
									
										
										
										
											2023-04-28 16:45:21 +01:00
										 |  |  | 		gtscontext.SetFastFail(ctx), | 
					
						
							| 
									
										
										
										
											2023-02-03 20:03:05 +00:00
										 |  |  | 		authed.Account.Username, | 
					
						
							|  |  |  | 		username, domain, false, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-05-29 19:39:43 +02:00
										 |  |  | } |