diff options
author | 2023-08-19 14:33:15 +0200 | |
---|---|---|
committer | 2023-08-19 14:33:15 +0200 | |
commit | 92de8fb396265d057f18aab4de0bc8aff4b90188 (patch) | |
tree | 46438b9ff550261f56aa58d038cdf2f1e15493e3 /internal/api/client | |
parent | [bugfix] fix double firing bun.DB query hooks (#2124) (diff) | |
download | gotosocial-92de8fb396265d057f18aab4de0bc8aff4b90188.tar.xz |
[feature] Instance rules (#2125)
* init instance rules database model, admin api
* expose instance rules in public instance api
* public /api/v1/instance/rules route
* GET ruleById
* createRule route
* createRule auth check
* updateRule
* deleteRule
* list rules on about page
* ruleGet auth
* add about page ids for anchors
* process and store adding violated rules to reports
* admin api models for instance rules
* instance rule edit frontend
* change rule inputs to textareas
* database fixes after rebase (#2124)
* remove unused imports
* fix db migration column name
* fix tests
* fix more tests
* fix postgres error with wrongly used Ident
* add some tests, fiddle with rule model a bit, fix postgres migration
* swagger docs
---------
Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
Diffstat (limited to 'internal/api/client')
-rw-r--r-- | internal/api/client/admin/admin.go | 41 | ||||
-rw-r--r-- | internal/api/client/admin/reportsget_test.go | 35 | ||||
-rw-r--r-- | internal/api/client/admin/rulecreate.go | 120 | ||||
-rw-r--r-- | internal/api/client/admin/ruledelete.go | 107 | ||||
-rw-r--r-- | internal/api/client/admin/ruleget.go | 102 | ||||
-rw-r--r-- | internal/api/client/admin/rulesget.go | 91 | ||||
-rw-r--r-- | internal/api/client/admin/ruleupdate.go | 127 | ||||
-rw-r--r-- | internal/api/client/instance/instance.go | 3 | ||||
-rw-r--r-- | internal/api/client/instance/instancepatch_test.go | 72 | ||||
-rw-r--r-- | internal/api/client/instance/instancerulesget.go | 71 | ||||
-rw-r--r-- | internal/api/client/reports/reportcreate_test.go | 6 | ||||
-rw-r--r-- | internal/api/client/reports/reportget_test.go | 5 | ||||
-rw-r--r-- | internal/api/client/reports/reportsget_test.go | 20 |
13 files changed, 764 insertions, 36 deletions
diff --git a/internal/api/client/admin/admin.go b/internal/api/client/admin/admin.go index a6c825b2b..ce6604c29 100644 --- a/internal/api/client/admin/admin.go +++ b/internal/api/client/admin/admin.go @@ -25,22 +25,24 @@ import ( ) const ( - BasePath = "/v1/admin" - EmojiPath = BasePath + "/custom_emojis" - EmojiPathWithID = EmojiPath + "/:" + IDKey - EmojiCategoriesPath = EmojiPath + "/categories" - DomainBlocksPath = BasePath + "/domain_blocks" - DomainBlocksPathWithID = DomainBlocksPath + "/:" + IDKey - AccountsPath = BasePath + "/accounts" - AccountsPathWithID = AccountsPath + "/:" + IDKey - AccountsActionPath = AccountsPathWithID + "/action" - MediaCleanupPath = BasePath + "/media_cleanup" - MediaRefetchPath = BasePath + "/media_refetch" - ReportsPath = BasePath + "/reports" - ReportsPathWithID = ReportsPath + "/:" + IDKey - ReportsResolvePath = ReportsPathWithID + "/resolve" - EmailPath = BasePath + "/email" - EmailTestPath = EmailPath + "/test" + BasePath = "/v1/admin" + EmojiPath = BasePath + "/custom_emojis" + EmojiPathWithID = EmojiPath + "/:" + IDKey + EmojiCategoriesPath = EmojiPath + "/categories" + DomainBlocksPath = BasePath + "/domain_blocks" + DomainBlocksPathWithID = DomainBlocksPath + "/:" + IDKey + AccountsPath = BasePath + "/accounts" + AccountsPathWithID = AccountsPath + "/:" + IDKey + AccountsActionPath = AccountsPathWithID + "/action" + MediaCleanupPath = BasePath + "/media_cleanup" + MediaRefetchPath = BasePath + "/media_refetch" + ReportsPath = BasePath + "/reports" + ReportsPathWithID = ReportsPath + "/:" + IDKey + ReportsResolvePath = ReportsPathWithID + "/resolve" + EmailPath = BasePath + "/email" + EmailTestPath = EmailPath + "/test" + InstanceRulesPath = BasePath + "/instance/rules" + InstanceRulesPathWithID = InstanceRulesPath + "/:" + IDKey IDKey = "id" FilterQueryKey = "filter" @@ -95,4 +97,11 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H // email stuff attachHandler(http.MethodPost, EmailTestPath, m.EmailTestPOSTHandler) + + // instance rules stuff + attachHandler(http.MethodGet, InstanceRulesPath, m.RulesGETHandler) + attachHandler(http.MethodGet, InstanceRulesPathWithID, m.RuleGETHandler) + attachHandler(http.MethodPost, InstanceRulesPath, m.RulePOSTHandler) + attachHandler(http.MethodPatch, InstanceRulesPathWithID, m.RulePATCHHandler) + attachHandler(http.MethodDelete, InstanceRulesPathWithID, m.RuleDELETEHandler) } diff --git a/internal/api/client/admin/reportsget_test.go b/internal/api/client/admin/reportsget_test.go index 943e9711a..4c714a9e0 100644 --- a/internal/api/client/admin/reportsget_test.go +++ b/internal/api/client/admin/reportsget_test.go @@ -335,7 +335,7 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() { "created_by_application_id": "01F8MGXQRHYF5QPMTMXP78QC2F" }, "statuses": [], - "rule_ids": [], + "rules": [], "action_taken_comment": "user was warned not to be a turtle anymore" }, { @@ -528,7 +528,16 @@ func (suite *ReportsGetTestSuite) TestReportsGetAll() { "poll": null } ], - "rule_ids": [], + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ], "action_taken_comment": null } ]`, string(b)) @@ -740,7 +749,16 @@ func (suite *ReportsGetTestSuite) TestReportsGetCreatedByAccount() { "poll": null } ], - "rule_ids": [], + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ], "action_taken_comment": null } ]`, string(b)) @@ -952,7 +970,16 @@ func (suite *ReportsGetTestSuite) TestReportsGetTargetAccount() { "poll": null } ], - "rule_ids": [], + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ], "action_taken_comment": null } ]`, string(b)) diff --git a/internal/api/client/admin/rulecreate.go b/internal/api/client/admin/rulecreate.go new file mode 100644 index 000000000..7792233f6 --- /dev/null +++ b/internal/api/client/admin/rulecreate.go @@ -0,0 +1,120 @@ +// 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 admin + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// RulePOSTHandler swagger:operation POST /api/v1/admin/instance/rules ruleCreate +// +// Create a new instance rule. +// +// --- +// tags: +// - admin +// +// consumes: +// - multipart/form-data +// +// produces: +// - application/json +// +// parameters: +// - +// name: text +// in: formData +// description: >- +// Text body for the instance rule, plaintext. +// type: string +// required: true +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: The newly-created instance rule. +// schema: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) RulePOSTHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(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 + } + + form := &apimodel.InstanceRuleCreateRequest{} + if err := c.ShouldBind(form); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if err := validateCreateRule(form); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + apiRule, errWithCode := m.processor.Admin().RuleCreate(c.Request.Context(), form) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, apiRule) +} + +func validateCreateRule(form *apimodel.InstanceRuleCreateRequest) error { + if form.Text == "" { + return errors.New("Instance rule text is empty") + } + + return nil +} diff --git a/internal/api/client/admin/ruledelete.go b/internal/api/client/admin/ruledelete.go new file mode 100644 index 000000000..7281ed62e --- /dev/null +++ b/internal/api/client/admin/ruledelete.go @@ -0,0 +1,107 @@ +// 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 admin + +import ( + "errors" + "fmt" + "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" +) + +// RuleDELETEHandler swagger:operation DELETE /api/v1/admin/instance/rules{id} ruleDelete +// +// Delete an existing instance rule. +// +// --- +// tags: +// - admin +// +// consumes: +// - multipart/form-data +// +// produces: +// - application/json +// +// parameters: +// - +// name: id +// in: formData +// description: >- +// The id of the rule to delete. +// type: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: The deleted instance rule. +// schema: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) RuleDELETEHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(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 + } + + ruleID := c.Param(IDKey) + if ruleID == "" { + err := errors.New("no rule id specified") + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + apiRule, errWithCode := m.processor.Admin().RuleDelete(c.Request.Context(), ruleID) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, apiRule) +} diff --git a/internal/api/client/admin/ruleget.go b/internal/api/client/admin/ruleget.go new file mode 100644 index 000000000..444820a3f --- /dev/null +++ b/internal/api/client/admin/ruleget.go @@ -0,0 +1,102 @@ +// 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 admin + +import ( + "errors" + "fmt" + "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" +) + +// RuleGETHandler swagger:operation GET /api/v1/admin/rules/{id} adminRuleGet +// +// View instance rule with the given id. +// +// --- +// tags: +// - admin +// +// produces: +// - application/json +// +// parameters: +// - +// name: id +// type: string +// description: The id of the rule. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// name: rule +// description: The requested rule. +// schema: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) RuleGETHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(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 + } + + ruleID := c.Param(IDKey) + if ruleID == "" { + err := errors.New("no rule id specified") + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + rule, errWithCode := m.processor.Admin().RuleGet(c.Request.Context(), ruleID) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, rule) +} diff --git a/internal/api/client/admin/rulesget.go b/internal/api/client/admin/rulesget.go new file mode 100644 index 000000000..56f83866f --- /dev/null +++ b/internal/api/client/admin/rulesget.go @@ -0,0 +1,91 @@ +// 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 admin + +import ( + "fmt" + "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" +) + +// rulesGETHandler swagger:operation GET /api/v1/admin/rules rules +// +// View instance rules, with IDs. +// +// The rules will be returned in order (sorted by Order ascending). +// +// --- +// tags: +// - admin +// +// produces: +// - application/json +// +// parameters: +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: An array with all the rules for the local instance. +// schema: +// type: array +// items: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) RulesGETHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(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 + } + + resp, errWithCode := m.processor.Admin().RulesGet(c.Request.Context()) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/client/admin/ruleupdate.go b/internal/api/client/admin/ruleupdate.go new file mode 100644 index 000000000..82ed41190 --- /dev/null +++ b/internal/api/client/admin/ruleupdate.go @@ -0,0 +1,127 @@ +// 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 admin + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// RulePATCHHandler swagger:operation PATCH /api/v1/admin/instance/rules{id} ruleUpdate +// +// Update an existing instance rule. +// +// --- +// tags: +// - admin +// +// consumes: +// - multipart/form-data +// +// produces: +// - application/json +// +// parameters: +// - +// name: id +// in: formData +// description: >- +// The id of the rule to update. +// type: path +// required: true +// - +// name: text +// in: formData +// description: >- +// Text body for the updated instance rule, plaintext. +// type: string +// required: true +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: The updated instance rule. +// schema: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) RulePATCHHandler(c *gin.Context) { + authed, err := oauth.Authed(c, true, true, true, true) + if err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1) + return + } + + if !*authed.User.Admin { + err := fmt.Errorf("user %s not an admin", authed.User.ID) + apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(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 + } + + ruleID := c.Param(IDKey) + if ruleID == "" { + err := errors.New("no rule id specified") + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + form := &apimodel.InstanceRuleCreateRequest{} + if err := c.ShouldBind(form); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + // reuses CreateRule validator + if err := validateCreateRule(form); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1) + return + } + + apiRule, errWithCode := m.processor.Admin().RuleUpdate(c.Request.Context(), ruleID, form) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, apiRule) +} diff --git a/internal/api/client/instance/instance.go b/internal/api/client/instance/instance.go index 8c58b62aa..82f6a4714 100644 --- a/internal/api/client/instance/instance.go +++ b/internal/api/client/instance/instance.go @@ -28,6 +28,7 @@ const ( InstanceInformationPathV1 = "/v1/instance" InstanceInformationPathV2 = "/v2/instance" InstancePeersPath = InstanceInformationPathV1 + "/peers" + InstanceRulesPath = InstanceInformationPathV1 + "/rules" PeersFilterKey = "filter" // PeersFilterKey is used to provide filters to /api/v1/instance/peers ) @@ -47,4 +48,6 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H attachHandler(http.MethodPatch, InstanceInformationPathV1, m.InstanceUpdatePATCHHandler) attachHandler(http.MethodGet, InstancePeersPath, m.InstancePeersGETHandler) + + attachHandler(http.MethodGet, InstanceRulesPath, m.InstanceRulesGETHandler) } diff --git a/internal/api/client/instance/instancepatch_test.go b/internal/api/client/instance/instancepatch_test.go index 11382f83a..a402f8347 100644 --- a/internal/api/client/instance/instancepatch_test.go +++ b/internal/api/client/instance/instancepatch_test.go @@ -160,7 +160,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) } @@ -264,7 +274,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) } @@ -368,7 +388,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) } @@ -523,7 +553,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) } @@ -651,7 +691,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) // extra bonus: check the v2 model thumbnail after the patch @@ -790,7 +840,17 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() { "name": "admin" } }, - "max_toot_chars": 5000 + "max_toot_chars": 5000, + "rules": [ + { + "id": "01GP3AWY4CRDVRNZKW0TEAMB51", + "text": "Be gay" + }, + { + "id": "01GP3DFY9XQ1TJMZT5BGAZPXX3", + "text": "Do crime" + } + ] }`, dst.String()) } diff --git a/internal/api/client/instance/instancerulesget.go b/internal/api/client/instance/instancerulesget.go new file mode 100644 index 000000000..5cc99ba41 --- /dev/null +++ b/internal/api/client/instance/instancerulesget.go @@ -0,0 +1,71 @@ +// 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 instance + +import ( + "net/http" + + "github.com/gin-gonic/gin" + apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util" + "github.com/superseriousbusiness/gotosocial/internal/gtserror" +) + +// instanceRulesGETHandler swagger:operation GET /api/v1/instance/rules rules +// +// View instance rules (public). +// +// The rules will be returned in order (sorted by Order ascending). +// +// --- +// tags: +// - instance +// +// produces: +// - application/json +// +// parameters: +// +// responses: +// '200': +// description: An array with all the rules for the local instance. +// schema: +// type: array +// items: +// "$ref": "#/definitions/instanceRule" +// '400': +// description: bad request +// '404': +// description: not found +// '406': +// description: not acceptable +// '500': +// description: internal server error +func (m *Module) InstanceRulesGETHandler(c *gin.Context) { + if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil { + apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1) + return + } + + resp, errWithCode := m.processor.InstanceGetRules(c.Request.Context()) + if errWithCode != nil { + apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1) + return + } + + c.JSON(http.StatusOK, resp) +} diff --git a/internal/api/client/reports/reportcreate_test.go b/internal/api/client/reports/reportcreate_test.go index e17695cb9..35dc3d015 100644 --- a/internal/api/client/reports/reportcreate_test.go +++ b/internal/api/client/reports/reportcreate_test.go @@ -51,17 +51,13 @@ func (suite *ReportCreateTestSuite) createReport(expectedHTTPStatus int, expecte // create the request ctx.Request = httptest.NewRequest(http.MethodPost, config.GetProtocol()+"://"+config.GetHost()+"/api/"+reports.BasePath, nil) ctx.Request.Header.Set("accept", "application/json") - ruleIDs := make([]string, 0, len(form.RuleIDs)) - for _, r := range form.RuleIDs { - ruleIDs = append(ruleIDs, strconv.Itoa(r)) - } ctx.Request.Form = url.Values{ "account_id": {form.AccountID}, "status_ids[]": form.StatusIDs, "comment": {form.Comment}, "forward": {strconv.FormatBool(form.Forward)}, "category": {form.Category}, - "rule_ids[]": ruleIDs, + "rule_ids[]": form.RuleIDs, } // trigger the handler diff --git a/internal/api/client/reports/reportget_test.go b/internal/api/client/reports/reportget_test.go index e29836b6a..1bdb7557c 100644 --- a/internal/api/client/reports/reportget_test.go +++ b/internal/api/client/reports/reportget_test.go @@ -108,7 +108,10 @@ func (suite *ReportGetTestSuite) TestGetReport1() { "status_ids": [ "01FVW7JHQFSFK166WWKR8CBA6M" ], - "rule_ids": [], + "rule_ids": [ + "01GP3AWY4CRDVRNZKW0TEAMB51", + "01GP3DFY9XQ1TJMZT5BGAZPXX3" + ], "target_account": { "id": "01F8MH5ZK5VRH73AKHQM6Y9VNX", "username": "foss_satan", diff --git a/internal/api/client/reports/reportsget_test.go b/internal/api/client/reports/reportsget_test.go index d220dc94d..e58a622db 100644 --- a/internal/api/client/reports/reportsget_test.go +++ b/internal/api/client/reports/reportsget_test.go @@ -133,7 +133,10 @@ func (suite *ReportsGetTestSuite) TestGetReports() { "status_ids": [ "01FVW7JHQFSFK166WWKR8CBA6M" ], - "rule_ids": [], + "rule_ids": [ + "01GP3AWY4CRDVRNZKW0TEAMB51", + "01GP3DFY9XQ1TJMZT5BGAZPXX3" + ], "target_account": { "id": "01F8MH5ZK5VRH73AKHQM6Y9VNX", "username": "foss_satan", @@ -220,7 +223,10 @@ func (suite *ReportsGetTestSuite) TestGetReports4() { "status_ids": [ "01FVW7JHQFSFK166WWKR8CBA6M" ], - "rule_ids": [], + "rule_ids": [ + "01GP3AWY4CRDVRNZKW0TEAMB51", + "01GP3DFY9XQ1TJMZT5BGAZPXX3" + ], "target_account": { "id": "01F8MH5ZK5VRH73AKHQM6Y9VNX", "username": "foss_satan", @@ -291,7 +297,10 @@ func (suite *ReportsGetTestSuite) TestGetReports6() { "status_ids": [ "01FVW7JHQFSFK166WWKR8CBA6M" ], - "rule_ids": [], + "rule_ids": [ + "01GP3AWY4CRDVRNZKW0TEAMB51", + "01GP3DFY9XQ1TJMZT5BGAZPXX3" + ], "target_account": { "id": "01F8MH5ZK5VRH73AKHQM6Y9VNX", "username": "foss_satan", @@ -346,7 +355,10 @@ func (suite *ReportsGetTestSuite) TestGetReports7() { "status_ids": [ "01FVW7JHQFSFK166WWKR8CBA6M" ], - "rule_ids": [], + "rule_ids": [ + "01GP3AWY4CRDVRNZKW0TEAMB51", + "01GP3DFY9XQ1TJMZT5BGAZPXX3" + ], "target_account": { "id": "01F8MH5ZK5VRH73AKHQM6Y9VNX", "username": "foss_satan", |