mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-17 21:47:32 -06:00
Merge branch 'main' into 2fa
This commit is contained in:
commit
c6c212fb81
271 changed files with 7226 additions and 11019 deletions
|
|
@ -107,9 +107,14 @@ func (p *Processor) Alias(
|
|||
}
|
||||
|
||||
// Ensure we have account dereferenced.
|
||||
//
|
||||
// As this comes from user input, allow checking
|
||||
// by URL to make things easier, not just to an
|
||||
// exact AP URI (which a user might not even know).
|
||||
targetAccount, _, err := p.federator.GetAccountByURI(ctx,
|
||||
account.Username,
|
||||
newAKA.uri,
|
||||
true,
|
||||
)
|
||||
if err != nil {
|
||||
err := fmt.Errorf(
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ func stubbifyAccount(account *gtsmodel.Account, origin string) []string {
|
|||
account.Fields = nil
|
||||
account.Note = ""
|
||||
account.NoteRaw = ""
|
||||
account.Memorial = util.Ptr(false)
|
||||
account.MemorializedAt = never
|
||||
account.AlsoKnownAsURIs = nil
|
||||
account.MovedToURI = ""
|
||||
account.Discoverable = util.Ptr(false)
|
||||
|
|
@ -546,7 +546,7 @@ func stubbifyAccount(account *gtsmodel.Account, origin string) []string {
|
|||
"fields",
|
||||
"note",
|
||||
"note_raw",
|
||||
"memorial",
|
||||
"memorialized_at",
|
||||
"also_known_as_uris",
|
||||
"moved_to_uri",
|
||||
"discoverable",
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func (suite *AccountDeleteTestSuite) TestAccountDeleteLocal() {
|
|||
suite.Nil(updatedAccount.Fields)
|
||||
suite.Zero(updatedAccount.Note)
|
||||
suite.Zero(updatedAccount.NoteRaw)
|
||||
suite.False(*updatedAccount.Memorial)
|
||||
suite.Zero(updatedAccount.MemorializedAt)
|
||||
suite.Empty(updatedAccount.AlsoKnownAsURIs)
|
||||
suite.False(*updatedAccount.Discoverable)
|
||||
suite.WithinDuration(time.Now(), updatedAccount.SuspendedAt, 1*time.Minute)
|
||||
|
|
|
|||
|
|
@ -66,10 +66,13 @@ func (p *Processor) Get(ctx context.Context, requestingAccount *gtsmodel.Account
|
|||
|
||||
// Perform a last-minute fetch of target account to
|
||||
// ensure remote account header / avatar is cached.
|
||||
//
|
||||
// Match by URI only.
|
||||
latest, _, err := p.federator.GetAccountByURI(
|
||||
gtscontext.SetFastFail(ctx),
|
||||
requestingAccount.Username,
|
||||
targetAccountURI,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error fetching latest target account: %v", err)
|
||||
|
|
|
|||
|
|
@ -119,11 +119,15 @@ func (p *Processor) MoveSelf(
|
|||
unlock := p.state.ProcessingLocks.Lock(lockKey)
|
||||
defer unlock()
|
||||
|
||||
// Ensure we have a valid, up-to-date representation of the target account.
|
||||
// Ensure we have a valid, up-to-date
|
||||
// representation of the target account.
|
||||
//
|
||||
// Match by uri only.
|
||||
targetAcct, targetAcctable, err = p.federator.GetAccountByURI(
|
||||
ctx,
|
||||
originAcct.Username,
|
||||
targetAcctURI,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
const text = "error dereferencing moved_to_uri"
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form
|
|||
}
|
||||
|
||||
if form.Bot != nil {
|
||||
account.Bot = form.Bot
|
||||
acctColumns = append(acctColumns, "bot")
|
||||
account.ActorType = gtsmodel.AccountActorTypeService
|
||||
acctColumns = append(acctColumns, "actor_type")
|
||||
}
|
||||
|
||||
if form.Locked != nil {
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func (p *Processor) createDomainAllow(
|
|||
}
|
||||
|
||||
// Insert the new allow into the database.
|
||||
if err := p.state.DB.CreateDomainAllow(ctx, domainAllow); err != nil {
|
||||
if err := p.state.DB.PutDomainAllow(ctx, domainAllow); err != nil {
|
||||
err = gtserror.Newf("db error putting domain allow %s: %w", domain, err)
|
||||
return nil, "", gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
|
@ -92,6 +92,54 @@ func (p *Processor) createDomainAllow(
|
|||
return apiDomainAllow, action.ID, nil
|
||||
}
|
||||
|
||||
func (p *Processor) updateDomainAllow(
|
||||
ctx context.Context,
|
||||
domainAllowID string,
|
||||
obfuscate *bool,
|
||||
publicComment *string,
|
||||
privateComment *string,
|
||||
subscriptionID *string,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
domainAllow, err := p.state.DB.GetDomainAllowByID(ctx, domainAllowID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, db.ErrNoEntries) {
|
||||
// Real error.
|
||||
err = gtserror.Newf("db error getting domain allow: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// There are just no entries for this ID.
|
||||
err = fmt.Errorf("no domain allow entry exists with ID %s", domainAllowID)
|
||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||
}
|
||||
|
||||
var columns []string
|
||||
if obfuscate != nil {
|
||||
domainAllow.Obfuscate = obfuscate
|
||||
columns = append(columns, "obfuscate")
|
||||
}
|
||||
if publicComment != nil {
|
||||
domainAllow.PublicComment = *publicComment
|
||||
columns = append(columns, "public_comment")
|
||||
}
|
||||
if privateComment != nil {
|
||||
domainAllow.PrivateComment = *privateComment
|
||||
columns = append(columns, "private_comment")
|
||||
}
|
||||
if subscriptionID != nil {
|
||||
domainAllow.SubscriptionID = *subscriptionID
|
||||
columns = append(columns, "subscription_id")
|
||||
}
|
||||
|
||||
// Update the domain allow.
|
||||
if err := p.state.DB.UpdateDomainAllow(ctx, domainAllow, columns...); err != nil {
|
||||
err = gtserror.Newf("db error updating domain allow: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return p.apiDomainPerm(ctx, domainAllow, false)
|
||||
}
|
||||
|
||||
func (p *Processor) deleteDomainAllow(
|
||||
ctx context.Context,
|
||||
adminAcct *gtsmodel.Account,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ func (p *Processor) createDomainBlock(
|
|||
}
|
||||
|
||||
// Insert the new block into the database.
|
||||
if err := p.state.DB.CreateDomainBlock(ctx, domainBlock); err != nil {
|
||||
if err := p.state.DB.PutDomainBlock(ctx, domainBlock); err != nil {
|
||||
err = gtserror.Newf("db error putting domain block %s: %w", domain, err)
|
||||
return nil, "", gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
|
@ -93,6 +93,54 @@ func (p *Processor) createDomainBlock(
|
|||
return apiDomainBlock, action.ID, nil
|
||||
}
|
||||
|
||||
func (p *Processor) updateDomainBlock(
|
||||
ctx context.Context,
|
||||
domainBlockID string,
|
||||
obfuscate *bool,
|
||||
publicComment *string,
|
||||
privateComment *string,
|
||||
subscriptionID *string,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
domainBlock, err := p.state.DB.GetDomainBlockByID(ctx, domainBlockID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, db.ErrNoEntries) {
|
||||
// Real error.
|
||||
err = gtserror.Newf("db error getting domain block: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
// There are just no entries for this ID.
|
||||
err = fmt.Errorf("no domain block entry exists with ID %s", domainBlockID)
|
||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||
}
|
||||
|
||||
var columns []string
|
||||
if obfuscate != nil {
|
||||
domainBlock.Obfuscate = obfuscate
|
||||
columns = append(columns, "obfuscate")
|
||||
}
|
||||
if publicComment != nil {
|
||||
domainBlock.PublicComment = *publicComment
|
||||
columns = append(columns, "public_comment")
|
||||
}
|
||||
if privateComment != nil {
|
||||
domainBlock.PrivateComment = *privateComment
|
||||
columns = append(columns, "private_comment")
|
||||
}
|
||||
if subscriptionID != nil {
|
||||
domainBlock.SubscriptionID = *subscriptionID
|
||||
columns = append(columns, "subscription_id")
|
||||
}
|
||||
|
||||
// Update the domain block.
|
||||
if err := p.state.DB.UpdateDomainBlock(ctx, domainBlock, columns...); err != nil {
|
||||
err = gtserror.Newf("db error updating domain block: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return p.apiDomainPerm(ctx, domainBlock, false)
|
||||
}
|
||||
|
||||
func (p *Processor) deleteDomainBlock(
|
||||
ctx context.Context,
|
||||
adminAcct *gtsmodel.Account,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
|
@ -29,6 +30,7 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
// DomainPermissionCreate creates an instance-level permission
|
||||
|
|
@ -84,6 +86,50 @@ func (p *Processor) DomainPermissionCreate(
|
|||
}
|
||||
}
|
||||
|
||||
// DomainPermissionUpdate updates a domain permission
|
||||
// of the given permissionType, with the given ID.
|
||||
func (p *Processor) DomainPermissionUpdate(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permID string,
|
||||
obfuscate *bool,
|
||||
publicComment *string,
|
||||
privateComment *string,
|
||||
subscriptionID *string,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
switch permissionType {
|
||||
|
||||
// Explicitly block a domain.
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
return p.updateDomainBlock(
|
||||
ctx,
|
||||
permID,
|
||||
obfuscate,
|
||||
publicComment,
|
||||
privateComment,
|
||||
subscriptionID,
|
||||
)
|
||||
|
||||
// Explicitly allow a domain.
|
||||
case gtsmodel.DomainPermissionAllow:
|
||||
return p.updateDomainAllow(
|
||||
ctx,
|
||||
permID,
|
||||
obfuscate,
|
||||
publicComment,
|
||||
privateComment,
|
||||
subscriptionID,
|
||||
)
|
||||
|
||||
// 🎵 Why don't we all strap bombs to our chests,
|
||||
// and ride our bikes to the next G7 picnic?
|
||||
// Seems easier with every clock-tick. 🎵
|
||||
default:
|
||||
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// DomainPermissionDelete removes one domain block with the given ID,
|
||||
// and processes side effects of removing the block asynchronously.
|
||||
//
|
||||
|
|
@ -153,14 +199,14 @@ func (p *Processor) DomainPermissionsImport(
|
|||
}
|
||||
defer file.Close()
|
||||
|
||||
// Parse file as slice of domain blocks.
|
||||
domainPerms := make([]*apimodel.DomainPermission, 0)
|
||||
if err := json.NewDecoder(file).Decode(&domainPerms); err != nil {
|
||||
// Parse file as slice of domain permissions.
|
||||
apiDomainPerms := make([]*apimodel.DomainPermission, 0)
|
||||
if err := json.NewDecoder(file).Decode(&apiDomainPerms); err != nil {
|
||||
err = gtserror.Newf("error parsing attachment as domain permissions: %w", err)
|
||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||
}
|
||||
|
||||
count := len(domainPerms)
|
||||
count := len(apiDomainPerms)
|
||||
if count == 0 {
|
||||
err = gtserror.New("error importing domain permissions: 0 entries provided")
|
||||
return nil, gtserror.NewErrorBadRequest(err, err.Error())
|
||||
|
|
@ -170,52 +216,97 @@ func (p *Processor) DomainPermissionsImport(
|
|||
// between successes and errors so that the caller can
|
||||
// try failed imports again if desired.
|
||||
multiStatusEntries := make([]apimodel.MultiStatusEntry, 0, count)
|
||||
|
||||
for _, domainPerm := range domainPerms {
|
||||
var (
|
||||
domain = domainPerm.Domain.Domain
|
||||
obfuscate = domainPerm.Obfuscate
|
||||
publicComment = domainPerm.PublicComment
|
||||
privateComment = domainPerm.PrivateComment
|
||||
subscriptionID = "" // No sub ID for imports.
|
||||
errWithCode gtserror.WithCode
|
||||
for _, apiDomainPerm := range apiDomainPerms {
|
||||
multiStatusEntries = append(
|
||||
multiStatusEntries,
|
||||
p.importOrUpdateDomainPerm(
|
||||
ctx,
|
||||
permissionType,
|
||||
account,
|
||||
apiDomainPerm,
|
||||
),
|
||||
)
|
||||
|
||||
domainPerm, _, errWithCode = p.DomainPermissionCreate(
|
||||
ctx,
|
||||
permissionType,
|
||||
account,
|
||||
domain,
|
||||
obfuscate,
|
||||
publicComment,
|
||||
privateComment,
|
||||
subscriptionID,
|
||||
)
|
||||
|
||||
var entry *apimodel.MultiStatusEntry
|
||||
|
||||
if errWithCode != nil {
|
||||
entry = &apimodel.MultiStatusEntry{
|
||||
// Use the failed domain entry as the resource value.
|
||||
Resource: domain,
|
||||
Message: errWithCode.Safe(),
|
||||
Status: errWithCode.Code(),
|
||||
}
|
||||
} else {
|
||||
entry = &apimodel.MultiStatusEntry{
|
||||
// Use successfully created API model domain block as the resource value.
|
||||
Resource: domainPerm,
|
||||
Message: http.StatusText(http.StatusOK),
|
||||
Status: http.StatusOK,
|
||||
}
|
||||
}
|
||||
|
||||
multiStatusEntries = append(multiStatusEntries, *entry)
|
||||
}
|
||||
|
||||
return apimodel.NewMultiStatus(multiStatusEntries), nil
|
||||
}
|
||||
|
||||
func (p *Processor) importOrUpdateDomainPerm(
|
||||
ctx context.Context,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
account *gtsmodel.Account,
|
||||
apiDomainPerm *apimodel.DomainPermission,
|
||||
) apimodel.MultiStatusEntry {
|
||||
var (
|
||||
domain = apiDomainPerm.Domain.Domain
|
||||
obfuscate = apiDomainPerm.Obfuscate
|
||||
publicComment = cmp.Or(apiDomainPerm.PublicComment, apiDomainPerm.Comment)
|
||||
privateComment = apiDomainPerm.PrivateComment
|
||||
subscriptionID = "" // No sub ID for imports.
|
||||
)
|
||||
|
||||
// Check if this domain
|
||||
// perm already exists.
|
||||
var (
|
||||
domainPerm gtsmodel.DomainPermission
|
||||
err error
|
||||
)
|
||||
if permType == gtsmodel.DomainPermissionBlock {
|
||||
domainPerm, err = p.state.DB.GetDomainBlock(ctx, domain)
|
||||
} else {
|
||||
domainPerm, err = p.state.DB.GetDomainAllow(ctx, domain)
|
||||
}
|
||||
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
// Real db error.
|
||||
return apimodel.MultiStatusEntry{
|
||||
Resource: domain,
|
||||
Message: "db error checking for existence of domain permission",
|
||||
Status: http.StatusInternalServerError,
|
||||
}
|
||||
}
|
||||
|
||||
var errWithCode gtserror.WithCode
|
||||
if domainPerm != nil {
|
||||
// Permission already exists, update it.
|
||||
apiDomainPerm, errWithCode = p.DomainPermissionUpdate(
|
||||
ctx,
|
||||
permType,
|
||||
domainPerm.GetID(),
|
||||
obfuscate,
|
||||
publicComment,
|
||||
privateComment,
|
||||
nil,
|
||||
)
|
||||
} else {
|
||||
// Permission didn't exist yet, create it.
|
||||
apiDomainPerm, _, errWithCode = p.DomainPermissionCreate(
|
||||
ctx,
|
||||
permType,
|
||||
account,
|
||||
domain,
|
||||
util.PtrOrZero(obfuscate),
|
||||
util.PtrOrZero(publicComment),
|
||||
util.PtrOrZero(privateComment),
|
||||
subscriptionID,
|
||||
)
|
||||
}
|
||||
|
||||
if errWithCode != nil {
|
||||
return apimodel.MultiStatusEntry{
|
||||
Resource: domain,
|
||||
Message: errWithCode.Safe(),
|
||||
Status: errWithCode.Code(),
|
||||
}
|
||||
}
|
||||
|
||||
return apimodel.MultiStatusEntry{
|
||||
Resource: apiDomainPerm,
|
||||
Message: http.StatusText(http.StatusOK),
|
||||
Status: http.StatusOK,
|
||||
}
|
||||
}
|
||||
|
||||
// DomainPermissionsGet returns all existing domain
|
||||
// permissions of the requested type. If export is
|
||||
// true, the format will be suitable for writing out
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ func (p *Processor) InstancePeersGet(ctx context.Context, includeSuspended bool,
|
|||
}
|
||||
|
||||
domains = append(domains, &apimodel.Domain{
|
||||
Domain: d,
|
||||
SuspendedAt: util.FormatISO8601(domainBlock.CreatedAt),
|
||||
PublicComment: domainBlock.PublicComment,
|
||||
Domain: d,
|
||||
SuspendedAt: util.FormatISO8601(domainBlock.CreatedAt),
|
||||
Comment: &domainBlock.PublicComment,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -490,7 +490,7 @@ func (p *Processor) byURI(
|
|||
|
||||
if includeAccounts(queryType) {
|
||||
// Check if URI points to an account.
|
||||
foundAccount, err := p.accountByURI(ctx, requestingAccount, uri, resolve)
|
||||
foundAccounts, err := p.accountsByURI(ctx, requestingAccount, uri, resolve)
|
||||
if err != nil {
|
||||
// Check for semi-expected error types.
|
||||
// On one of these, we can continue.
|
||||
|
|
@ -508,7 +508,9 @@ func (p *Processor) byURI(
|
|||
} else {
|
||||
// Hit! Return early since it's extremely unlikely
|
||||
// a status and an account will have the same URL.
|
||||
appendAccount(foundAccount)
|
||||
for _, foundAccount := range foundAccounts {
|
||||
appendAccount(foundAccount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -544,35 +546,42 @@ func (p *Processor) byURI(
|
|||
return nil
|
||||
}
|
||||
|
||||
// accountByURI looks for one account with the given URI.
|
||||
// accountsByURI looks for one account with the given URI/ID,
|
||||
// then if nothing is found, multiple accounts with the given URL.
|
||||
//
|
||||
// If resolve is false, it will only look in the database.
|
||||
// If resolve is true, it will try to resolve the account
|
||||
// from remote using the URI, if necessary.
|
||||
//
|
||||
// Will return either a hit, ErrNotRetrievable, ErrWrongType,
|
||||
// or a real error that the caller should handle.
|
||||
func (p *Processor) accountByURI(
|
||||
func (p *Processor) accountsByURI(
|
||||
ctx context.Context,
|
||||
requestingAccount *gtsmodel.Account,
|
||||
uri *url.URL,
|
||||
resolve bool,
|
||||
) (*gtsmodel.Account, error) {
|
||||
) ([]*gtsmodel.Account, error) {
|
||||
if resolve {
|
||||
// We're allowed to resolve, leave the
|
||||
// rest up to the dereferencer functions.
|
||||
//
|
||||
// Allow dereferencing by URL and not just URI;
|
||||
// there are many cases where someone might
|
||||
// paste a URL into the search bar.
|
||||
account, _, err := p.federator.GetAccountByURI(
|
||||
gtscontext.SetFastFail(ctx),
|
||||
requestingAccount.Username,
|
||||
uri,
|
||||
true,
|
||||
)
|
||||
|
||||
return account, err
|
||||
return []*gtsmodel.Account{account}, err
|
||||
}
|
||||
|
||||
// We're not allowed to resolve; search database only.
|
||||
uriStr := uri.String() // stringify uri just once
|
||||
|
||||
// Search by ActivityPub URI.
|
||||
// Search for single acct by ActivityPub URI.
|
||||
account, err := p.state.DB.GetAccountByURI(ctx, uriStr)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err = gtserror.Newf("error checking database for account using URI %s: %w", uriStr, err)
|
||||
|
|
@ -581,22 +590,22 @@ func (p *Processor) accountByURI(
|
|||
|
||||
if account != nil {
|
||||
// We got a hit! No need to continue.
|
||||
return account, nil
|
||||
return []*gtsmodel.Account{account}, nil
|
||||
}
|
||||
|
||||
// No hit yet. Fallback to try by URL.
|
||||
account, err = p.state.DB.GetAccountByURL(ctx, uriStr)
|
||||
// No hit yet. Fallback to look for any accounts with URL.
|
||||
accounts, err := p.state.DB.GetAccountsByURL(ctx, uriStr)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err = gtserror.Newf("error checking database for account using URL %s: %w", uriStr, err)
|
||||
err = gtserror.Newf("error checking database for accounts using URL %s: %w", uriStr, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if account != nil {
|
||||
// We got a hit! No need to continue.
|
||||
return account, nil
|
||||
if len(accounts) != 0 {
|
||||
// We got hits! No need to continue.
|
||||
return accounts, nil
|
||||
}
|
||||
|
||||
err = fmt.Errorf("account %s could not be retrieved locally and we cannot resolve", uriStr)
|
||||
err = fmt.Errorf("account(s) %s could not be retrieved locally and we cannot resolve", uriStr)
|
||||
return nil, gtserror.SetUnretrievable(err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -303,10 +303,13 @@ func (p *fediAPI) MoveAccount(ctx context.Context, fMsg *messages.FromFediAPI) e
|
|||
}
|
||||
|
||||
// Account to which the Move is taking place.
|
||||
//
|
||||
// Match by uri only.
|
||||
targetAcct, targetAcctable, err := p.federate.GetAccountByURI(
|
||||
ctx,
|
||||
fMsg.Receiving.Username,
|
||||
targetAcctURI,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue