diff options
Diffstat (limited to 'internal/api/client/accounts')
-rw-r--r-- | internal/api/client/accounts/account_test.go | 9 | ||||
-rw-r--r-- | internal/api/client/accounts/accounts.go | 5 | ||||
-rw-r--r-- | internal/api/client/accounts/lists.go | 97 | ||||
-rw-r--r-- | internal/api/client/accounts/lists_test.go | 103 |
4 files changed, 212 insertions, 2 deletions
diff --git a/internal/api/client/accounts/account_test.go b/internal/api/client/accounts/account_test.go index b168f216c..678fc8a5d 100644 --- a/internal/api/client/accounts/account_test.go +++ b/internal/api/client/accounts/account_test.go @@ -36,6 +36,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/processing" "github.com/superseriousbusiness/gotosocial/internal/state" "github.com/superseriousbusiness/gotosocial/internal/storage" + "github.com/superseriousbusiness/gotosocial/internal/visibility" "github.com/superseriousbusiness/gotosocial/testrig" ) @@ -86,6 +87,12 @@ func (suite *AccountStandardTestSuite) SetupTest() { suite.storage = testrig.NewInMemoryStorage() suite.state.Storage = suite.storage + testrig.StartTimelines( + &suite.state, + visibility.NewFilter(&suite.state), + testrig.NewTestTypeConverter(suite.db), + ) + suite.mediaManager = testrig.NewTestMediaManager(&suite.state) suite.federator = testrig.NewTestFederator(&suite.state, testrig.NewTestTransportController(&suite.state, testrig.NewMockHTTPClient(nil, "../../../../testrig/media")), suite.mediaManager) suite.sentEmails = make(map[string]string) @@ -94,8 +101,6 @@ func (suite *AccountStandardTestSuite) SetupTest() { suite.accountsModule = accounts.New(suite.processor) testrig.StandardDBSetup(suite.db, nil) testrig.StandardStorageSetup(suite.storage, "../../../../testrig/media") - - suite.NoError(suite.processor.Start()) } func (suite *AccountStandardTestSuite) TearDownTest() { diff --git a/internal/api/client/accounts/accounts.go b/internal/api/client/accounts/accounts.go index a6bedd6e1..298104a8d 100644 --- a/internal/api/client/accounts/accounts.go +++ b/internal/api/client/accounts/accounts.go @@ -70,6 +70,8 @@ const ( UnblockPath = BasePathWithID + "/unblock" // DeleteAccountPath is for deleting one's account via the API DeleteAccountPath = BasePath + "/delete" + // ListsPath is for seeing which lists an account is. + ListsPath = BasePathWithID + "/lists" ) type Module struct { @@ -115,4 +117,7 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H // block or unblock account attachHandler(http.MethodPost, BlockPath, m.AccountBlockPOSTHandler) attachHandler(http.MethodPost, UnblockPath, m.AccountUnblockPOSTHandler) + + // account lists + attachHandler(http.MethodGet, ListsPath, m.AccountListsGETHandler) } diff --git a/internal/api/client/accounts/lists.go b/internal/api/client/accounts/lists.go new file mode 100644 index 000000000..4ce1bf729 --- /dev/null +++ b/internal/api/client/accounts/lists.go @@ -0,0 +1,97 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package accounts + +import ( + "errors" + "net/http" + + "github.com/gin-gonic/gin" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// AccountListsGETHandler swagger:operation GET /api/v1/accounts/{id}/lists accountLists +// +// See all lists of yours that contain requested account. +// +// --- +// tags: +// - accounts +// +// produces: +// - application/json +// +// parameters: +// - +// name: id +// type: string +// description: Account ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:lists +// +// responses: +// '200': +// name: lists +// description: Array of all lists containing this account. +// schema: +// type: array +// items: +// "$ref": "#/definitions/list" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) AccountListsGETHandler(c *gin.Context) { + authed, err := oauth.Authed(c, false, false, false, false) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1) + return + } + + targetAcctID := c.Param(IDKey) + if targetAcctID == "" { + err := errors.New("no account id specified") + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + lists, errWithCode := m.processor.Account().ListsGet(c.Request.Context(), authed.Account, targetAcctID) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, lists) +} diff --git a/internal/api/client/accounts/lists_test.go b/internal/api/client/accounts/lists_test.go new file mode 100644 index 000000000..6984d6ef8 --- /dev/null +++ b/internal/api/client/accounts/lists_test.go @@ -0,0 +1,103 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package accounts_test + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/suite" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/oauth" + "github.com/superseriousbusiness/gotosocial/testrig" +) + +type ListsTestSuite struct { + AccountStandardTestSuite +} + +func (suite *ListsTestSuite) getLists(targetAccountID string, expectedHTTPStatus int, expectedBody string) []*apimodel.List { + var ( + recorder = httptest.NewRecorder() + ctx, _ = testrig.CreateGinTestContext(recorder, nil) + request = httptest.NewRequest(http.MethodGet, "http://localhost:8080/api/v1/accounts/"+targetAccountID+"/lists", nil) + ) + + // Set up the test context. + ctx.Request = request + ctx.AddParam("id", targetAccountID) + ctx.Set(oauth.SessionAuthorizedAccount, suite.testAccounts["local_account_1"]) + ctx.Set(oauth.SessionAuthorizedToken, oauth.DBTokenToToken(suite.testTokens["local_account_1"])) + ctx.Set(oauth.SessionAuthorizedApplication, suite.testApplications["application_1"]) + ctx.Set(oauth.SessionAuthorizedUser, suite.testUsers["local_account_1"]) + + // Trigger the handler. + suite.accountsModule.AccountListsGETHandler(ctx) + + // Read the result. + result := recorder.Result() + defer result.Body.Close() + + b, err := io.ReadAll(result.Body) + if err != nil { + suite.FailNow(err.Error()) + } + + errs := gtserror.MultiError{} + + // Check expected code + body. + if resultCode := recorder.Code; expectedHTTPStatus != resultCode { + errs = append(errs, fmt.Sprintf("expected %d got %d", expectedHTTPStatus, resultCode)) + } + + // If we got an expected body, return early. + if expectedBody != "" && string(b) != expectedBody { + errs = append(errs, fmt.Sprintf("expected %s got %s", expectedBody, string(b))) + } + + if err := errs.Combine(); err != nil { + suite.FailNow("", "%v (body %s)", err, string(b)) + } + + // Return list response. + resp := new([]*apimodel.List) + if err := json.Unmarshal(b, resp); err != nil { + suite.FailNow(err.Error()) + } + + return *resp +} + +func (suite *ListsTestSuite) TestGetListsHit() { + targetAccount := suite.testAccounts["admin_account"] + suite.getLists(targetAccount.ID, http.StatusOK, `[{"id":"01H0G8E4Q2J3FE3JDWJVWEDCD1","title":"Cool Ass Posters From This Instance","replies_policy":"followed"}]`) +} + +func (suite *ListsTestSuite) TestGetListsNoHit() { + targetAccount := suite.testAccounts["remote_account_1"] + suite.getLists(targetAccount.ID, http.StatusOK, `[]`) +} + +func TestListsTestSuite(t *testing.T) { + suite.Run(t, new(ListsTestSuite)) +} |