From 8ae2440da3a9b66c379c5a9444b50e758deef61b Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Sun, 6 Apr 2025 14:39:40 +0200 Subject: [chore] Migrate accounts to new table, relax uniqueness constraint of actor `url` and collections (#3928) * [chore] Migrate accounts to new table, relax uniqueness constraint of actor url and collections * fiddle with it! (that's what she said) * remove unused cache fields * sillyness * fix tiny whoopsie --- internal/processing/account/alias.go | 5 ++++ internal/processing/account/delete.go | 4 +-- internal/processing/account/delete_test.go | 2 +- internal/processing/account/get.go | 3 ++ internal/processing/account/move.go | 6 +++- internal/processing/account/update.go | 4 +-- internal/processing/search/get.go | 39 +++++++++++++++---------- internal/processing/workers/fromfediapi_move.go | 3 ++ 8 files changed, 45 insertions(+), 21 deletions(-) (limited to 'internal/processing') diff --git a/internal/processing/account/alias.go b/internal/processing/account/alias.go index d7d4cf547..ca27a518c 100644 --- a/internal/processing/account/alias.go +++ b/internal/processing/account/alias.go @@ -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( diff --git a/internal/processing/account/delete.go b/internal/processing/account/delete.go index ab64c3270..2d3ef88de 100644 --- a/internal/processing/account/delete.go +++ b/internal/processing/account/delete.go @@ -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", diff --git a/internal/processing/account/delete_test.go b/internal/processing/account/delete_test.go index ee6fe1dfc..587071a11 100644 --- a/internal/processing/account/delete_test.go +++ b/internal/processing/account/delete_test.go @@ -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) diff --git a/internal/processing/account/get.go b/internal/processing/account/get.go index eac0f0c3f..33eb4c101 100644 --- a/internal/processing/account/get.go +++ b/internal/processing/account/get.go @@ -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) diff --git a/internal/processing/account/move.go b/internal/processing/account/move.go index 1c5209e70..c8665cf04 100644 --- a/internal/processing/account/move.go +++ b/internal/processing/account/move.go @@ -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" diff --git a/internal/processing/account/update.go b/internal/processing/account/update.go index a833d72c1..60d2cb8f6 100644 --- a/internal/processing/account/update.go +++ b/internal/processing/account/update.go @@ -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 { diff --git a/internal/processing/search/get.go b/internal/processing/search/get.go index d1462cf53..7a65bed1d 100644 --- a/internal/processing/search/get.go +++ b/internal/processing/search/get.go @@ -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) } diff --git a/internal/processing/workers/fromfediapi_move.go b/internal/processing/workers/fromfediapi_move.go index d1e43c0c7..d2f06de5d 100644 --- a/internal/processing/workers/fromfediapi_move.go +++ b/internal/processing/workers/fromfediapi_move.go @@ -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( -- cgit v1.2.3