gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

lookup.go (3859B)


      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 	"errors"
     23 	"fmt"
     24 	"strings"
     25 
     26 	errorsv2 "codeberg.org/gruf/go-errors/v2"
     27 	"codeberg.org/gruf/go-kv"
     28 	apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
     29 	"github.com/superseriousbusiness/gotosocial/internal/federation/dereferencing"
     30 	"github.com/superseriousbusiness/gotosocial/internal/gtserror"
     31 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     32 	"github.com/superseriousbusiness/gotosocial/internal/log"
     33 	"github.com/superseriousbusiness/gotosocial/internal/util"
     34 )
     35 
     36 // Lookup does a quick, non-resolving search for accounts that
     37 // match the given query. It expects input that looks like a
     38 // namestring, and will normalize plaintext to look more like
     39 // a namestring. Will only ever return one account, and only on
     40 // an exact match.
     41 //
     42 // This behavior aligns more or less with Mastodon's API.
     43 // See https://docs.joinmastodon.org/methods/accounts/#lookup
     44 func (p *Processor) Lookup(
     45 	ctx context.Context,
     46 	requestingAccount *gtsmodel.Account,
     47 	query string,
     48 ) (*apimodel.Account, gtserror.WithCode) {
     49 	// Validate query.
     50 	query = strings.TrimSpace(query)
     51 	if query == "" {
     52 		err := errors.New("search query was empty string after trimming space")
     53 		return nil, gtserror.NewErrorBadRequest(err, err.Error())
     54 	}
     55 
     56 	// Be nice and normalize query by prepending '@'.
     57 	// This will make it easier for accountsByNamestring
     58 	// to pick this up as a valid namestring.
     59 	if query[0] != '@' {
     60 		query = "@" + query
     61 	}
     62 
     63 	log.
     64 		WithContext(ctx).
     65 		WithFields(kv.Fields{
     66 			{"query", query},
     67 		}...).
     68 		Debugf("beginning search")
     69 
     70 	// See if we have something that looks like a namestring.
     71 	username, domain, err := util.ExtractNamestringParts(query)
     72 	if err != nil {
     73 		err := errors.New("bad search query, must in the form '[username]' or '[username]@[domain]")
     74 		return nil, gtserror.NewErrorBadRequest(err, err.Error())
     75 	}
     76 
     77 	account, err := p.accountByUsernameDomain(
     78 		ctx,
     79 		requestingAccount,
     80 		username,
     81 		domain,
     82 		false, // never resolve!
     83 	)
     84 	if err != nil {
     85 		if errorsv2.Assignable(err, (*dereferencing.ErrNotRetrievable)(nil)) {
     86 			// ErrNotRetrievable is fine, just wrap it in
     87 			// a 404 to indicate we couldn't find anything.
     88 			err := fmt.Errorf("%s not found", query)
     89 			return nil, gtserror.NewErrorNotFound(err, err.Error())
     90 		}
     91 
     92 		// Real error has occurred.
     93 		err = gtserror.Newf("error looking up %s as account: %w", query, err)
     94 		return nil, gtserror.NewErrorInternalError(err)
     95 	}
     96 
     97 	// If we reach this point, we found an account. Shortcut
     98 	// using the packageAccounts function to return it. This
     99 	// may cause the account to be filtered out if it's not
    100 	// visible to the caller, so anticipate this.
    101 	accounts, errWithCode := p.packageAccounts(ctx, requestingAccount, []*gtsmodel.Account{account})
    102 	if errWithCode != nil {
    103 		return nil, errWithCode
    104 	}
    105 
    106 	if len(accounts) == 0 {
    107 		// Account was not visible to the requesting account.
    108 		err := fmt.Errorf("%s not found", query)
    109 		return nil, gtserror.NewErrorNotFound(err, err.Error())
    110 	}
    111 
    112 	// We got a hit!
    113 	return accounts[0], nil
    114 }