util.go (4646B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package search 19 20 import ( 21 "context" 22 23 apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" 24 "github.com/superseriousbusiness/gotosocial/internal/gtserror" 25 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 26 "github.com/superseriousbusiness/gotosocial/internal/log" 27 ) 28 29 // return true if given queryType should include accounts. 30 func includeAccounts(queryType string) bool { 31 return queryType == queryTypeAny || queryType == queryTypeAccounts 32 } 33 34 // return true if given queryType should include statuses. 35 func includeStatuses(queryType string) bool { 36 return queryType == queryTypeAny || queryType == queryTypeStatuses 37 } 38 39 // packageAccounts is a util function that just 40 // converts the given accounts into an apimodel 41 // account slice, or errors appropriately. 42 func (p *Processor) packageAccounts( 43 ctx context.Context, 44 requestingAccount *gtsmodel.Account, 45 accounts []*gtsmodel.Account, 46 ) ([]*apimodel.Account, gtserror.WithCode) { 47 apiAccounts := make([]*apimodel.Account, 0, len(accounts)) 48 49 for _, account := range accounts { 50 if account.IsInstance() { 51 // No need to show instance accounts. 52 continue 53 } 54 55 // Ensure requester can see result account. 56 visible, err := p.filter.AccountVisible(ctx, requestingAccount, account) 57 if err != nil { 58 err = gtserror.Newf("error checking visibility of account %s for account %s: %w", account.ID, requestingAccount.ID, err) 59 return nil, gtserror.NewErrorInternalError(err) 60 } 61 62 if !visible { 63 log.Debugf(ctx, "account %s is not visible to account %s, skipping this result", account.ID, requestingAccount.ID) 64 continue 65 } 66 67 apiAccount, err := p.tc.AccountToAPIAccountPublic(ctx, account) 68 if err != nil { 69 log.Debugf(ctx, "skipping account %s because it couldn't be converted to its api representation: %s", account.ID, err) 70 continue 71 } 72 73 apiAccounts = append(apiAccounts, apiAccount) 74 } 75 76 return apiAccounts, nil 77 } 78 79 // packageStatuses is a util function that just 80 // converts the given statuses into an apimodel 81 // status slice, or errors appropriately. 82 func (p *Processor) packageStatuses( 83 ctx context.Context, 84 requestingAccount *gtsmodel.Account, 85 statuses []*gtsmodel.Status, 86 ) ([]*apimodel.Status, gtserror.WithCode) { 87 apiStatuses := make([]*apimodel.Status, 0, len(statuses)) 88 89 for _, status := range statuses { 90 // Ensure requester can see result status. 91 visible, err := p.filter.StatusVisible(ctx, requestingAccount, status) 92 if err != nil { 93 err = gtserror.Newf("error checking visibility of status %s for account %s: %w", status.ID, requestingAccount.ID, err) 94 return nil, gtserror.NewErrorInternalError(err) 95 } 96 97 if !visible { 98 log.Debugf(ctx, "status %s is not visible to account %s, skipping this result", status.ID, requestingAccount.ID) 99 continue 100 } 101 102 apiStatus, err := p.tc.StatusToAPIStatus(ctx, status, requestingAccount) 103 if err != nil { 104 log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", status.ID, err) 105 continue 106 } 107 108 apiStatuses = append(apiStatuses, apiStatus) 109 } 110 111 return apiStatuses, nil 112 } 113 114 // packageSearchResult wraps up the given accounts 115 // and statuses into an apimodel SearchResult that 116 // can be serialized to an API caller as JSON. 117 func (p *Processor) packageSearchResult( 118 ctx context.Context, 119 requestingAccount *gtsmodel.Account, 120 accounts []*gtsmodel.Account, 121 statuses []*gtsmodel.Status, 122 ) (*apimodel.SearchResult, gtserror.WithCode) { 123 apiAccounts, errWithCode := p.packageAccounts(ctx, requestingAccount, accounts) 124 if errWithCode != nil { 125 return nil, errWithCode 126 } 127 128 apiStatuses, errWithCode := p.packageStatuses(ctx, requestingAccount, statuses) 129 if errWithCode != nil { 130 return nil, errWithCode 131 } 132 133 return &apimodel.SearchResult{ 134 Accounts: apiAccounts, 135 Statuses: apiStatuses, 136 Hashtags: make([]*apimodel.Tag, 0), 137 }, nil 138 }