From c8a780e12a8112a4d4cbe8ed72d241a382f73903 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:36:40 +0200 Subject: [PATCH] [bugfix] Fix setting bot on/off (#3986) * [bugfix] Fix setting bot on/off * read client messages in tests * test fix --- internal/gtsmodel/account.go | 2 +- internal/processing/account/update.go | 12 ++++- internal/processing/account/update_test.go | 59 ++++++++++++++++++++++ internal/typeutils/internaltoas.go | 43 +++++++++------- internal/typeutils/internaltoas_test.go | 4 +- 5 files changed, 97 insertions(+), 23 deletions(-) diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go index d681304ba..c2ab1c9a4 100644 --- a/internal/gtsmodel/account.go +++ b/internal/gtsmodel/account.go @@ -431,7 +431,7 @@ func (t AccountActorType) String() string { case AccountActorTypeService: return "Service" default: - panic("invalid notification type") + panic("invalid actor type") } } diff --git a/internal/processing/account/update.go b/internal/processing/account/update.go index 60d2cb8f6..83a046a25 100644 --- a/internal/processing/account/update.go +++ b/internal/processing/account/update.go @@ -77,8 +77,16 @@ func (p *Processor) Update(ctx context.Context, account *gtsmodel.Account, form acctColumns = append(acctColumns, "discoverable") } - if form.Bot != nil { - account.ActorType = gtsmodel.AccountActorTypeService + if bot := form.Bot; bot != nil { + if *bot { + // Mark account as an Application. + // See: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application + account.ActorType = gtsmodel.AccountActorTypeApplication + } else { + // Mark account as a Person. + // See: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person + account.ActorType = gtsmodel.AccountActorTypePerson + } acctColumns = append(acctColumns, "actor_type") } diff --git a/internal/processing/account/update_test.go b/internal/processing/account/update_test.go index a07562544..674502b75 100644 --- a/internal/processing/account/update_test.go +++ b/internal/processing/account/update_test.go @@ -26,6 +26,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/ap" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + "github.com/superseriousbusiness/gotosocial/internal/util" ) type AccountUpdateTestSuite struct { @@ -331,6 +332,64 @@ func (suite *AccountUpdateTestSuite) TestAccountUpdateNoteNotFields() { suite.Equal(fieldsBefore, len(dbAccount.Fields)) } +func (suite *AccountUpdateTestSuite) TestAccountUpdateBotNotBot() { + testAccount := >smodel.Account{} + *testAccount = *suite.testAccounts["local_account_1"] + ctx := context.Background() + + // Call update function to set bot = true. + apiAccount, errWithCode := suite.accountProcessor.Update( + ctx, + testAccount, + &apimodel.UpdateCredentialsRequest{ + Bot: util.Ptr(true), + }, + ) + if errWithCode != nil { + suite.FailNow(errWithCode.Error()) + } + + // Returned profile should be updated. + suite.True(apiAccount.Bot) + + // We should have an update in the client api channel. + msg, _ := suite.getClientMsg(5 * time.Second) + suite.NotNil(msg) + + // Check database model of account as well. + dbAccount, err := suite.db.GetAccountByID(ctx, testAccount.ID) + if err != nil { + suite.FailNow(err.Error()) + } + suite.True(dbAccount.ActorType.IsBot()) + + // Call update function to set bot = false. + apiAccount, errWithCode = suite.accountProcessor.Update( + ctx, + testAccount, + &apimodel.UpdateCredentialsRequest{ + Bot: util.Ptr(false), + }, + ) + if errWithCode != nil { + suite.FailNow(errWithCode.Error()) + } + + // Returned profile should be updated. + suite.False(apiAccount.Bot) + + // We should have an update in the client api channel. + msg, _ = suite.getClientMsg(5 * time.Second) + suite.NotNil(msg) + + // Check database model of account as well. + dbAccount, err = suite.db.GetAccountByID(ctx, testAccount.ID) + if err != nil { + suite.FailNow(err.Error()) + } + suite.False(dbAccount.ActorType.IsBot()) +} + func TestAccountUpdateTestSuite(t *testing.T) { suite.Run(t, new(AccountUpdateTestSuite)) } diff --git a/internal/typeutils/internaltoas.go b/internal/typeutils/internaltoas.go index 4e6c6da77..9d9a7e289 100644 --- a/internal/typeutils/internaltoas.go +++ b/internal/typeutils/internaltoas.go @@ -39,20 +39,32 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util/xslices" ) -// AccountToAS converts a gts model account -// into an activity streams person or service. +func accountableForActorType(actorType gtsmodel.AccountActorType) ap.Accountable { + switch actorType { + case gtsmodel.AccountActorTypeApplication: + return streams.NewActivityStreamsApplication() + case gtsmodel.AccountActorTypeGroup: + return streams.NewActivityStreamsGroup() + case gtsmodel.AccountActorTypeOrganization: + return streams.NewActivityStreamsOrganization() + case gtsmodel.AccountActorTypePerson: + return streams.NewActivityStreamsPerson() + case gtsmodel.AccountActorTypeService: + return streams.NewActivityStreamsService() + default: + panic("invalid actor type") + } +} + +// AccountToAS converts a gts model +// account into an accountable. func (c *Converter) AccountToAS( ctx context.Context, a *gtsmodel.Account, ) (ap.Accountable, error) { - // accountable is a service if this - // is a bot account, otherwise a person. - var accountable ap.Accountable - if a.ActorType.IsBot() { - accountable = streams.NewActivityStreamsService() - } else { - accountable = streams.NewActivityStreamsPerson() - } + // Use appropriate underlying + // actor type of accountable. + accountable := accountableForActorType(a.ActorType) // id should be the activitypub URI of this user // something like https://example.org/users/example_user @@ -389,14 +401,9 @@ func (c *Converter) AccountToASMinimal( ctx context.Context, a *gtsmodel.Account, ) (ap.Accountable, error) { - // accountable is a service if this - // is a bot account, otherwise a person. - var accountable ap.Accountable - if a.ActorType.IsBot() { - accountable = streams.NewActivityStreamsService() - } else { - accountable = streams.NewActivityStreamsPerson() - } + // Use appropriate underlying + // actor type of accountable. + accountable := accountableForActorType(a.ActorType) // id should be the activitypub URI of this user // something like https://example.org/users/example_user diff --git a/internal/typeutils/internaltoas_test.go b/internal/typeutils/internaltoas_test.go index 0db705ca7..7c05a14b8 100644 --- a/internal/typeutils/internaltoas_test.go +++ b/internal/typeutils/internaltoas_test.go @@ -99,7 +99,7 @@ func (suite *InternalToASTestSuite) TestAccountToASBot() { *testAccount = *suite.testAccounts["local_account_1"] // take zork for this test // Update zork to be a bot. - testAccount.ActorType = gtsmodel.AccountActorTypeService + testAccount.ActorType = gtsmodel.AccountActorTypeApplication if err := suite.state.DB.UpdateAccount(context.Background(), testAccount); err != nil { suite.FailNow(err.Error()) } @@ -155,7 +155,7 @@ func (suite *InternalToASTestSuite) TestAccountToASBot() { "published": "2022-05-20T11:09:18Z", "summary": "\u003cp\u003ehey yo this is my profile!\u003c/p\u003e", "tag": [], - "type": "Service", + "type": "Application", "url": "http://localhost:8080/@the_mighty_zork" }`, string(bytes)) }