diff options
Diffstat (limited to 'internal/api/client/admin')
-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 |
7 files changed, 603 insertions, 20 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) +} |