commit 878ed48de34365474498365ab11e3a0feb646be3
parent 11e843a27368f89847f1d6222001004214801ecf
Author: tobi <31960611+tsmethurst@users.noreply.github.com>
Date: Tue, 9 May 2023 17:05:35 +0200
[bugfix] Don't try to get user when serializing local instance account (#1757)
Diffstat:
4 files changed, 139 insertions(+), 29 deletions(-)
diff --git a/internal/api/client/search/searchget_test.go b/internal/api/client/search/searchget_test.go
@@ -235,6 +235,23 @@ func (suite *SearchGetTestSuite) TestSearchLocalAccountByURI() {
suite.NotNil(gotAccount)
}
+func (suite *SearchGetTestSuite) TestSearchLocalInstanceAccountByURI() {
+ query := "http://localhost:8080/users/localhost:8080"
+ resolve := false
+
+ searchResult, err := suite.testSearch(query, resolve, http.StatusOK)
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
+
+ if !suite.Len(searchResult.Accounts, 1) {
+ suite.FailNow("expected 1 account in search results but got 0")
+ }
+
+ gotAccount := searchResult.Accounts[0]
+ suite.NotNil(gotAccount)
+}
+
func (suite *SearchGetTestSuite) TestSearchLocalAccountByURL() {
query := "http://localhost:8080/@the_mighty_zork"
resolve := false
diff --git a/internal/gtsmodel/account.go b/internal/gtsmodel/account.go
@@ -95,6 +95,12 @@ func (a *Account) IsRemote() bool {
// IsInstance returns whether account is an instance internal actor account.
func (a *Account) IsInstance() bool {
+ if a.IsLocal() {
+ // Check if our instance account.
+ return a.Username == config.GetHost()
+ }
+
+ // Check if remote instance account.
return a.Username == a.Domain ||
a.FollowersURI == "" ||
a.FollowingURI == "" ||
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
@@ -171,22 +171,26 @@ func (c *converter) AccountToAPIAccountPublic(ctx context.Context, a *gtsmodel.A
acct = a.Username + "@" + d
} else {
- // This is a local user.
- acct = a.Username
+ // This is a local account, try to
+ // fetch more info. Skip for instance
+ // accounts since they have no user.
+ if !a.IsInstance() {
+ user, err := c.db.GetUserByAccountID(ctx, a.ID)
+ if err != nil {
+ return nil, fmt.Errorf("AccountToAPIAccountPublic: error getting user from database for account id %s: %w", a.ID, err)
+ }
- user, err := c.db.GetUserByAccountID(ctx, a.ID)
- if err != nil {
- return nil, fmt.Errorf("AccountToAPIAccountPublic: error getting user from database for account id %s: %w", a.ID, err)
+ switch {
+ case *user.Admin:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleAdmin}
+ case *user.Moderator:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleModerator}
+ default:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
+ }
}
- switch {
- case *user.Admin:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleAdmin}
- case *user.Moderator:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleModerator}
- default:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
- }
+ acct = a.Username // omit domain
}
// Remaining properties are simple and
@@ -257,27 +261,31 @@ func (c *converter) AccountToAPIAccountBlocked(ctx context.Context, a *gtsmodel.
// de-punify it just in case.
d, err := util.DePunify(a.Domain)
if err != nil {
- return nil, fmt.Errorf("AccountToAPIAccountPublic: error de-punifying domain %s for account id %s: %w", a.Domain, a.ID, err)
+ return nil, fmt.Errorf("AccountToAPIAccountBlocked: error de-punifying domain %s for account id %s: %w", a.Domain, a.ID, err)
}
acct = a.Username + "@" + d
} else {
- // This is a local user.
- acct = a.Username
+ // This is a local account, try to
+ // fetch more info. Skip for instance
+ // accounts since they have no user.
+ if !a.IsInstance() {
+ user, err := c.db.GetUserByAccountID(ctx, a.ID)
+ if err != nil {
+ return nil, fmt.Errorf("AccountToAPIAccountPublic: error getting user from database for account id %s: %w", a.ID, err)
+ }
- user, err := c.db.GetUserByAccountID(ctx, a.ID)
- if err != nil {
- return nil, fmt.Errorf("AccountToAPIAccountPublic: error getting user from database for account id %s: %s", a.ID, err)
+ switch {
+ case *user.Admin:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleAdmin}
+ case *user.Moderator:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleModerator}
+ default:
+ role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
+ }
}
- switch {
- case *user.Admin:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleAdmin}
- case *user.Moderator:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleModerator}
- default:
- role = &apimodel.AccountRole{Name: apimodel.AccountRoleUser}
- }
+ acct = a.Username // omit domain
}
return &apimodel.Account{
@@ -307,7 +315,6 @@ func (c *converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
createdByApplicationID string
)
- // take user-level information if possible
if a.IsRemote() {
// Domain may be in Punycode,
// de-punify it just in case.
@@ -317,7 +324,9 @@ func (c *converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
}
domain = &d
- } else {
+ } else if !a.IsInstance() {
+ // This is a local, non-instance
+ // acct; we can fetch more info.
user, err := c.db.GetUserByAccountID(ctx, a.ID)
if err != nil {
return nil, fmt.Errorf("AccountToAdminAPIAccount: error getting user from database for account id %s: %w", a.ID, err)
@@ -337,11 +346,13 @@ func (c *converter) AccountToAdminAPIAccount(ctx context.Context, a *gtsmodel.Ac
if user.Account.Reason != "" {
inviteRequest = &user.Account.Reason
}
+
if *user.Admin {
role.Name = apimodel.AccountRoleAdmin
} else if *user.Moderator {
role.Name = apimodel.AccountRoleModerator
}
+
confirmed = !user.ConfirmedAt.IsZero()
approved = *user.Approved
disabled = *user.Disabled
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
@@ -248,6 +248,82 @@ func (suite *InternalToFrontendTestSuite) TestAccountToFrontendPublicPunycode()
}`, string(b))
}
+func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendPublic() {
+ ctx := context.Background()
+ testAccount, err := suite.db.GetInstanceAccount(ctx, "")
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
+
+ apiAccount, err := suite.typeconverter.AccountToAPIAccountPublic(ctx, testAccount)
+ suite.NoError(err)
+ suite.NotNil(apiAccount)
+
+ b, err := json.MarshalIndent(apiAccount, "", " ")
+ suite.NoError(err)
+
+ suite.Equal(`{
+ "id": "01AY6P665V14JJR0AFVRT7311Y",
+ "username": "localhost:8080",
+ "acct": "localhost:8080",
+ "display_name": "",
+ "locked": false,
+ "discoverable": true,
+ "bot": false,
+ "created_at": "2020-05-17T13:10:59.000Z",
+ "note": "",
+ "url": "http://localhost:8080/@localhost:8080",
+ "avatar": "",
+ "avatar_static": "",
+ "header": "http://localhost:8080/assets/default_header.png",
+ "header_static": "http://localhost:8080/assets/default_header.png",
+ "followers_count": 0,
+ "following_count": 0,
+ "statuses_count": 0,
+ "last_status_at": null,
+ "emojis": [],
+ "fields": []
+}`, string(b))
+}
+
+func (suite *InternalToFrontendTestSuite) TestLocalInstanceAccountToFrontendBlocked() {
+ ctx := context.Background()
+ testAccount, err := suite.db.GetInstanceAccount(ctx, "")
+ if err != nil {
+ suite.FailNow(err.Error())
+ }
+
+ apiAccount, err := suite.typeconverter.AccountToAPIAccountBlocked(ctx, testAccount)
+ suite.NoError(err)
+ suite.NotNil(apiAccount)
+
+ b, err := json.MarshalIndent(apiAccount, "", " ")
+ suite.NoError(err)
+
+ suite.Equal(`{
+ "id": "01AY6P665V14JJR0AFVRT7311Y",
+ "username": "localhost:8080",
+ "acct": "localhost:8080",
+ "display_name": "",
+ "locked": false,
+ "discoverable": false,
+ "bot": false,
+ "created_at": "2020-05-17T13:10:59.000Z",
+ "note": "",
+ "url": "http://localhost:8080/@localhost:8080",
+ "avatar": "",
+ "avatar_static": "",
+ "header": "",
+ "header_static": "",
+ "followers_count": 0,
+ "following_count": 0,
+ "statuses_count": 0,
+ "last_status_at": null,
+ "emojis": null,
+ "fields": null
+}`, string(b))
+}
+
func (suite *InternalToFrontendTestSuite) TestStatusToFrontend() {
testStatus := suite.testStatuses["admin_account_status_1"]
requestingAccount := suite.testAccounts["local_account_1"]