summaryrefslogtreecommitdiff
path: root/internal/api
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2024-11-21 14:09:58 +0100
committerLibravatar GitHub <noreply@github.com>2024-11-21 13:09:58 +0000
commit301543616b5376585a7caff097499421acdf1806 (patch)
tree4cac6aea2c33687b1339fc3bc18e6eb64def6f9a /internal/api
parent[feature] Allow emoji shortcode to be 1-character length (#3556) (diff)
downloadgotosocial-301543616b5376585a7caff097499421acdf1806.tar.xz
[feature] Add domain permission drafts and excludes (#3547)
* [feature] Add domain permission drafts and excludes * fix typescript complaining * lint * make filenames more consistent * test own domain excluded
Diffstat (limited to 'internal/api')
-rw-r--r--internal/api/client/admin/admin.go81
-rw-r--r--internal/api/client/admin/domainpermissiondraftaccept.go134
-rw-r--r--internal/api/client/admin/domainpermissiondraftcreate.go176
-rw-r--r--internal/api/client/admin/domainpermissiondraftget.go104
-rw-r--r--internal/api/client/admin/domainpermissiondraftremove.go134
-rw-r--r--internal/api/client/admin/domainpermissiondraftsget.go189
-rw-r--r--internal/api/client/admin/domainpermissionexcludecreate.go138
-rw-r--r--internal/api/client/admin/domainpermissionexcludeget.go104
-rw-r--r--internal/api/client/admin/domainpermissionexcluderemove.go110
-rw-r--r--internal/api/client/admin/domainpermissionexcludesget.go159
-rw-r--r--internal/api/model/domain.go17
-rw-r--r--internal/api/util/parsequery.go7
12 files changed, 1314 insertions, 39 deletions
diff --git a/internal/api/client/admin/admin.go b/internal/api/client/admin/admin.go
index 2c55de2f0..a33a6448a 100644
--- a/internal/api/client/admin/admin.go
+++ b/internal/api/client/admin/admin.go
@@ -28,37 +28,43 @@ import (
)
const (
- BasePath = "/v1/admin"
- EmojiPath = BasePath + "/custom_emojis"
- EmojiPathWithID = EmojiPath + "/:" + apiutil.IDKey
- EmojiCategoriesPath = EmojiPath + "/categories"
- DomainBlocksPath = BasePath + "/domain_blocks"
- DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
- DomainAllowsPath = BasePath + "/domain_allows"
- DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
- DomainKeysExpirePath = BasePath + "/domain_keys_expire"
- HeaderAllowsPath = BasePath + "/header_allows"
- HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
- HeaderBlocksPath = BasePath + "/header_blocks"
- HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + apiutil.IDKey
- AccountsV1Path = BasePath + "/accounts"
- AccountsV2Path = "/v2/admin/accounts"
- AccountsPathWithID = AccountsV1Path + "/:" + apiutil.IDKey
- AccountsActionPath = AccountsPathWithID + "/action"
- AccountsApprovePath = AccountsPathWithID + "/approve"
- AccountsRejectPath = AccountsPathWithID + "/reject"
- MediaCleanupPath = BasePath + "/media_cleanup"
- MediaRefetchPath = BasePath + "/media_refetch"
- ReportsPath = BasePath + "/reports"
- ReportsPathWithID = ReportsPath + "/:" + apiutil.IDKey
- ReportsResolvePath = ReportsPathWithID + "/resolve"
- EmailPath = BasePath + "/email"
- EmailTestPath = EmailPath + "/test"
- InstanceRulesPath = BasePath + "/instance/rules"
- InstanceRulesPathWithID = InstanceRulesPath + "/:" + apiutil.IDKey
- DebugPath = BasePath + "/debug"
- DebugAPUrlPath = DebugPath + "/apurl"
- DebugClearCachesPath = DebugPath + "/caches/clear"
+ BasePath = "/v1/admin"
+ EmojiPath = BasePath + "/custom_emojis"
+ EmojiPathWithID = EmojiPath + "/:" + apiutil.IDKey
+ EmojiCategoriesPath = EmojiPath + "/categories"
+ DomainBlocksPath = BasePath + "/domain_blocks"
+ DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
+ DomainAllowsPath = BasePath + "/domain_allows"
+ DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
+ DomainPermissionDraftsPath = BasePath + "/domain_permission_drafts"
+ DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
+ DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
+ DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
+ DomainPermissionExcludesPath = BasePath + "/domain_permission_excludes"
+ DomainPermissionExcludesPathWithID = DomainPermissionExcludesPath + "/:" + apiutil.IDKey
+ DomainKeysExpirePath = BasePath + "/domain_keys_expire"
+ HeaderAllowsPath = BasePath + "/header_allows"
+ HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
+ HeaderBlocksPath = BasePath + "/header_blocks"
+ HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + apiutil.IDKey
+ AccountsV1Path = BasePath + "/accounts"
+ AccountsV2Path = "/v2/admin/accounts"
+ AccountsPathWithID = AccountsV1Path + "/:" + apiutil.IDKey
+ AccountsActionPath = AccountsPathWithID + "/action"
+ AccountsApprovePath = AccountsPathWithID + "/approve"
+ AccountsRejectPath = AccountsPathWithID + "/reject"
+ MediaCleanupPath = BasePath + "/media_cleanup"
+ MediaRefetchPath = BasePath + "/media_refetch"
+ ReportsPath = BasePath + "/reports"
+ ReportsPathWithID = ReportsPath + "/:" + apiutil.IDKey
+ ReportsResolvePath = ReportsPathWithID + "/resolve"
+ EmailPath = BasePath + "/email"
+ EmailTestPath = EmailPath + "/test"
+ InstanceRulesPath = BasePath + "/instance/rules"
+ InstanceRulesPathWithID = InstanceRulesPath + "/:" + apiutil.IDKey
+ DebugPath = BasePath + "/debug"
+ DebugAPUrlPath = DebugPath + "/apurl"
+ DebugClearCachesPath = DebugPath + "/caches/clear"
FilterQueryKey = "filter"
MaxShortcodeDomainKey = "max_shortcode_domain"
@@ -99,6 +105,19 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
attachHandler(http.MethodGet, DomainAllowsPathWithID, m.DomainAllowGETHandler)
attachHandler(http.MethodDelete, DomainAllowsPathWithID, m.DomainAllowDELETEHandler)
+ // domain permission draft stuff
+ attachHandler(http.MethodPost, DomainPermissionDraftsPath, m.DomainPermissionDraftsPOSTHandler)
+ attachHandler(http.MethodGet, DomainPermissionDraftsPath, m.DomainPermissionDraftsGETHandler)
+ attachHandler(http.MethodGet, DomainPermissionDraftsPathWithID, m.DomainPermissionDraftGETHandler)
+ attachHandler(http.MethodPost, DomainPermissionDraftAcceptPath, m.DomainPermissionDraftAcceptPOSTHandler)
+ attachHandler(http.MethodPost, DomainPermissionDraftRemovePath, m.DomainPermissionDraftRemovePOSTHandler)
+
+ // domain permission excludes stuff
+ attachHandler(http.MethodPost, DomainPermissionExcludesPath, m.DomainPermissionExcludesPOSTHandler)
+ attachHandler(http.MethodGet, DomainPermissionExcludesPath, m.DomainPermissionExcludesGETHandler)
+ attachHandler(http.MethodGet, DomainPermissionExcludesPathWithID, m.DomainPermissionExcludeGETHandler)
+ attachHandler(http.MethodDelete, DomainPermissionExcludesPathWithID, m.DomainPermissionExcludeDELETEHandler)
+
// header filtering administration routes
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
diff --git a/internal/api/client/admin/domainpermissiondraftaccept.go b/internal/api/client/admin/domainpermissiondraftaccept.go
new file mode 100644
index 000000000..5e484cbf3
--- /dev/null
+++ b/internal/api/client/admin/domainpermissiondraftaccept.go
@@ -0,0 +1,134 @@
+// 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"
+)
+
+// DomainPermissionDraftAcceptPOSTHandler swagger:operation POST /api/v1/admin/domain_permission_drafts/{id}/accept domainPermissionDraftAccept
+//
+// Accept a domain permission draft, turning it into an enforced domain permission.
+//
+// ---
+// tags:
+// - admin
+//
+// consumes:
+// - multipart/form-data
+// - application/json
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: id
+// required: true
+// in: path
+// description: ID of the domain permission draft.
+// type: string
+// -
+// name: overwrite
+// in: formData
+// description: >-
+// If a domain permission already exists with the same
+// domain and permission type as the draft, overwrite
+// the existing permission with fields from the draft.
+// type: boolean
+// default: false
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: The newly created domain permission.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '400':
+// description: bad request
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '406':
+// description: not acceptable
+// '409':
+// description: conflict
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionDraftAcceptPOSTHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ type AcceptForm struct {
+ Overwrite bool `json:"overwrite" form:"overwrite"`
+ }
+
+ form := new(AcceptForm)
+ if err := c.ShouldBind(form); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ domainPerm, _, errWithCode := m.processor.Admin().DomainPermissionDraftAccept(
+ c.Request.Context(),
+ authed.Account,
+ id,
+ form.Overwrite,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, domainPerm)
+}
diff --git a/internal/api/client/admin/domainpermissiondraftcreate.go b/internal/api/client/admin/domainpermissiondraftcreate.go
new file mode 100644
index 000000000..d20842ebf
--- /dev/null
+++ b/internal/api/client/admin/domainpermissiondraftcreate.go
@@ -0,0 +1,176 @@
+// 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/gtsmodel"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+)
+
+// DomainPermissionDraftsPOSTHandler swagger:operation POST /api/v1/admin/domain_permission_drafts domainPermissionDraftCreate
+//
+// Create a domain permission draft with the given parameters.
+//
+// ---
+// tags:
+// - admin
+//
+// consumes:
+// - multipart/form-data
+// - application/json
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: domain
+// in: formData
+// description: Domain to create the permission draft for.
+// type: string
+// -
+// name: permission_type
+// in: formData
+// description: Create a draft "allow" or a draft "block".
+// type: string
+// -
+// name: obfuscate
+// in: formData
+// description: >-
+// Obfuscate the name of the domain when serving it publicly.
+// Eg., `example.org` becomes something like `ex***e.org`.
+// type: boolean
+// -
+// name: public_comment
+// in: formData
+// description: >-
+// Public comment about this domain permission.
+// This will be displayed alongside the domain permission if you choose to share permissions.
+// type: string
+// -
+// name: private_comment
+// in: formData
+// description: >-
+// Private comment about this domain permission. Will only be shown to other admins, so this
+// is a useful way of internally keeping track of why a certain domain ended up permissioned.
+// type: string
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: The newly created domain permission draft.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '400':
+// description: bad request
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '406':
+// description: not acceptable
+// '409':
+// description: conflict
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionDraftsPOSTHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ // Parse + validate form.
+ form := new(apimodel.DomainPermissionRequest)
+ if err := c.ShouldBind(form); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ if form.Domain == "" {
+ const errText = "domain must be set"
+ errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ var (
+ permType gtsmodel.DomainPermissionType
+ errText string
+ )
+
+ switch pt := form.PermissionType; pt {
+ case "block":
+ permType = gtsmodel.DomainPermissionBlock
+ case "allow":
+ permType = gtsmodel.DomainPermissionAllow
+ case "":
+ errText = "permission_type not set, must be one of block or allow"
+ default:
+ errText = fmt.Sprintf("permission_type %s not recognized, must be one of block or allow", pt)
+ }
+
+ if errText != "" {
+ errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ permDraft, errWithCode := m.processor.Admin().DomainPermissionDraftCreate(
+ c.Request.Context(),
+ authed.Account,
+ form.Domain,
+ permType,
+ form.Obfuscate,
+ form.PublicComment,
+ form.PrivateComment,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, permDraft)
+}
diff --git a/internal/api/client/admin/domainpermissiondraftget.go b/internal/api/client/admin/domainpermissiondraftget.go
new file mode 100644
index 000000000..aef3b094b
--- /dev/null
+++ b/internal/api/client/admin/domainpermissiondraftget.go
@@ -0,0 +1,104 @@
+// 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"
+)
+
+// DomainPermissionDraftGETHandler swagger:operation GET /api/v1/admin/domain_permission_drafts/{id} domainPermissionDraftGet
+//
+// Get domain permission draft with the given ID.
+//
+// ---
+// tags:
+// - admin
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: id
+// required: true
+// in: path
+// description: ID of the domain permission draft.
+// type: string
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: Domain permission draft.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '404':
+// description: not found
+// '406':
+// description: not acceptable
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionDraftGETHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ permDraft, errWithCode := m.processor.Admin().DomainPermissionDraftGet(c.Request.Context(), id)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, permDraft)
+}
diff --git a/internal/api/client/admin/domainpermissiondraftremove.go b/internal/api/client/admin/domainpermissiondraftremove.go
new file mode 100644
index 000000000..78169508c
--- /dev/null
+++ b/internal/api/client/admin/domainpermissiondraftremove.go
@@ -0,0 +1,134 @@
+// 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"
+)
+
+// DomainPermissionDraftRemovePOSTHandler swagger:operation POST /api/v1/admin/domain_permission_drafts/{id}/remove domainPermissionDraftRemove
+//
+// Remove a domain permission draft, optionally ignoring all future drafts targeting the given domain.
+//
+// ---
+// tags:
+// - admin
+//
+// consumes:
+// - multipart/form-data
+// - application/json
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: id
+// required: true
+// in: path
+// description: ID of the domain permission draft.
+// type: string
+// -
+// name: exclude_target
+// in: formData
+// description: >-
+// When removing the domain permission draft, also create a
+// domain exclude entry for the target domain, so that drafts
+// will not be created for this domain in the future.
+// type: boolean
+// default: false
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: The removed domain permission draft.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '400':
+// description: bad request
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '406':
+// description: not acceptable
+// '409':
+// description: conflict
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionDraftRemovePOSTHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ type RemoveForm struct {
+ ExcludeTarget bool `json:"exclude_target" form:"exclude_target"`
+ }
+
+ form := new(RemoveForm)
+ if err := c.ShouldBind(form); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ domainPerm, errWithCode := m.processor.Admin().DomainPermissionDraftRemove(
+ c.Request.Context(),
+ authed.Account,
+ id,
+ form.ExcludeTarget,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, domainPerm)
+}
diff --git a/internal/api/client/admin/domainpermissiondraftsget.go b/internal/api/client/admin/domainpermissiondraftsget.go
new file mode 100644
index 000000000..dd3315857
--- /dev/null
+++ b/internal/api/client/admin/domainpermissiondraftsget.go
@@ -0,0 +1,189 @@
+// 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/gtsmodel"
+ "github.com/superseriousbusiness/gotosocial/internal/oauth"
+ "github.com/superseriousbusiness/gotosocial/internal/paging"
+)
+
+// DomainPermissionDraftsGETHandler swagger:operation GET /api/v1/admin/domain_permission_drafts domainPermissionDraftsGet
+//
+// View domain permission drafts.
+//
+// The drafts will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer).
+//
+// The next and previous queries can be parsed from the returned Link header.
+//
+// Example:
+//
+// ```
+// <https://example.org/api/v1/admin/domain_permission_drafts?limit=20&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/admin/domain_permission_drafts?limit=20&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
+// ````
+//
+// ---
+// tags:
+// - admin
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: subscription_id
+// type: string
+// description: Show only drafts created by the given subscription ID.
+// in: query
+// -
+// name: domain
+// type: string
+// description: Return only drafts that target the given domain.
+// in: query
+// -
+// name: permission_type
+// type: string
+// description: Filter on "block" or "allow" type drafts.
+// in: query
+// -
+// name: max_id
+// type: string
+// description: >-
+// Return only items *OLDER* than the given max ID (for paging downwards).
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: since_id
+// type: string
+// description: >-
+// Return only items *NEWER* than the given since ID.
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: min_id
+// type: string
+// description: >-
+// Return only items immediately *NEWER* than the given min ID (for paging upwards).
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: limit
+// type: integer
+// description: Number of items to return.
+// default: 20
+// minimum: 1
+// maximum: 100
+// in: query
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: Domain permission drafts.
+// schema:
+// type: array
+// items:
+// "$ref": "#/definitions/domainPermission"
+// headers:
+// Link:
+// type: string
+// description: Links to the next and previous queries.
+// '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) DomainPermissionDraftsGETHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ permType := c.Query(apiutil.DomainPermissionPermTypeKey)
+ switch permType {
+ case "", "block", "allow":
+ // No problem.
+
+ default:
+ // Invalid.
+ text := fmt.Sprintf(
+ "permission_type %s not recognized, valid values are empty string, block, or allow",
+ permType,
+ )
+ errWithCode := gtserror.NewErrorBadRequest(errors.New(text), text)
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ page, errWithCode := paging.ParseIDPage(c, 1, 200, 20)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ resp, errWithCode := m.processor.Admin().DomainPermissionDraftsGet(
+ c.Request.Context(),
+ c.Query(apiutil.DomainPermissionSubscriptionIDKey),
+ c.Query(apiutil.DomainPermissionDomainKey),
+ gtsmodel.NewDomainPermissionType(permType),
+ page,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ if resp.LinkHeader != "" {
+ c.Header("Link", resp.LinkHeader)
+ }
+
+ apiutil.JSON(c, http.StatusOK, resp.Items)
+}
diff --git a/internal/api/client/admin/domainpermissionexcludecreate.go b/internal/api/client/admin/domainpermissionexcludecreate.go
new file mode 100644
index 000000000..dd0b3b493
--- /dev/null
+++ b/internal/api/client/admin/domainpermissionexcludecreate.go
@@ -0,0 +1,138 @@
+// 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"
+)
+
+// DomainPermissionExcludesPOSTHandler swagger:operation POST /api/v1/admin/domain_permission_excludes domainPermissionExcludeCreate
+//
+// Create a domain permission exclude with the given parameters.
+//
+// Excluded domains (and their subdomains) will not be automatically blocked or allowed when a list of domain permissions is imported or subscribed to.
+//
+// You can still manually create domain blocks or domain allows for excluded domains, and any new or existing domain blocks or domain allows for an excluded domain will still be enforced.
+//
+// ---
+// tags:
+// - admin
+//
+// consumes:
+// - multipart/form-data
+// - application/json
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: domain
+// in: formData
+// description: Domain to create the permission exclude for.
+// type: string
+// -
+// name: private_comment
+// in: formData
+// description: >-
+// Private comment about this domain exclude.
+// type: string
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: The newly created domain permission exclude.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '400':
+// description: bad request
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '406':
+// description: not acceptable
+// '409':
+// description: conflict
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionExcludesPOSTHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ // Parse + validate form.
+ type ExcludeForm struct {
+ Domain string `form:"domain" json:"domain"`
+ PrivateComment string `form:"private_comment" json:"private_comment"`
+ }
+
+ form := new(ExcludeForm)
+ if err := c.ShouldBind(form); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ if form.Domain == "" {
+ const errText = "domain must be set"
+ errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ permExclude, errWithCode := m.processor.Admin().DomainPermissionExcludeCreate(
+ c.Request.Context(),
+ authed.Account,
+ form.Domain,
+ form.PrivateComment,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, permExclude)
+}
diff --git a/internal/api/client/admin/domainpermissionexcludeget.go b/internal/api/client/admin/domainpermissionexcludeget.go
new file mode 100644
index 000000000..ca110abd5
--- /dev/null
+++ b/internal/api/client/admin/domainpermissionexcludeget.go
@@ -0,0 +1,104 @@
+// 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"
+)
+
+// DomainPermissionExcludeGETHandler swagger:operation GET /api/v1/admin/domain_permission_excludes/{id} domainPermissionExcludeGet
+//
+// Get domain permission exclude with the given ID.
+//
+// ---
+// tags:
+// - admin
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: id
+// required: true
+// in: path
+// description: ID of the domain permission exclude.
+// type: string
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: Domain permission exclude.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '404':
+// description: not found
+// '406':
+// description: not acceptable
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionExcludeGETHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ permExclude, errWithCode := m.processor.Admin().DomainPermissionExcludeGet(c.Request.Context(), id)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, permExclude)
+}
diff --git a/internal/api/client/admin/domainpermissionexcluderemove.go b/internal/api/client/admin/domainpermissionexcluderemove.go
new file mode 100644
index 000000000..a167ae5a5
--- /dev/null
+++ b/internal/api/client/admin/domainpermissionexcluderemove.go
@@ -0,0 +1,110 @@
+// 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"
+)
+
+// DomainPermissionExcludeDELETEHandler swagger:operation DELETE /api/v1/admin/domain_permission_excludes/{id} domainPermissionExcludeDelete
+//
+// Remove a domain permission exclude.
+//
+// ---
+// tags:
+// - admin
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: id
+// required: true
+// in: path
+// description: ID of the domain permission exclude.
+// type: string
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: The removed domain permission exclude.
+// schema:
+// "$ref": "#/definitions/domainPermission"
+// '400':
+// description: bad request
+// '401':
+// description: unauthorized
+// '403':
+// description: forbidden
+// '406':
+// description: not acceptable
+// '409':
+// description: conflict
+// '500':
+// description: internal server error
+func (m *Module) DomainPermissionExcludeDELETEHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ domainPerm, errWithCode := m.processor.Admin().DomainPermissionExcludeRemove(
+ c.Request.Context(),
+ authed.Account,
+ id,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ apiutil.JSON(c, http.StatusOK, domainPerm)
+}
diff --git a/internal/api/client/admin/domainpermissionexcludesget.go b/internal/api/client/admin/domainpermissionexcludesget.go
new file mode 100644
index 000000000..71eedec52
--- /dev/null
+++ b/internal/api/client/admin/domainpermissionexcludesget.go
@@ -0,0 +1,159 @@
+// 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"
+ "github.com/superseriousbusiness/gotosocial/internal/paging"
+)
+
+// DomainPermissionExcludesGETHandler swagger:operation GET /api/v1/admin/domain_permission_excludes domainPermissionExcludesGet
+//
+// View domain permission excludes.
+//
+// The excludes will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer).
+//
+// The next and previous queries can be parsed from the returned Link header.
+//
+// Example:
+//
+// ```
+// <https://example.org/api/v1/admin/domain_permission_excludes?limit=20&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/admin/domain_permission_excludes?limit=20&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
+// ````
+//
+// ---
+// tags:
+// - admin
+//
+// produces:
+// - application/json
+//
+// parameters:
+// -
+// name: domain
+// type: string
+// description: Return only excludes that target the given domain.
+// in: query
+// -
+// name: max_id
+// type: string
+// description: >-
+// Return only items *OLDER* than the given max ID (for paging downwards).
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: since_id
+// type: string
+// description: >-
+// Return only items *NEWER* than the given since ID.
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: min_id
+// type: string
+// description: >-
+// Return only items immediately *NEWER* than the given min ID (for paging upwards).
+// The item with the specified ID will not be included in the response.
+// in: query
+// -
+// name: limit
+// type: integer
+// description: Number of items to return.
+// default: 20
+// minimum: 1
+// maximum: 100
+// in: query
+//
+// security:
+// - OAuth2 Bearer:
+// - admin
+//
+// responses:
+// '200':
+// description: Domain permission excludes.
+// schema:
+// type: array
+// items:
+// "$ref": "#/definitions/domainPermission"
+// headers:
+// Link:
+// type: string
+// description: Links to the next and previous queries.
+// '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) DomainPermissionExcludesGETHandler(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 authed.Account.IsMoving() {
+ apiutil.ForbiddenAfterMove(c)
+ return
+ }
+
+ if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
+ apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
+ return
+ }
+
+ page, errWithCode := paging.ParseIDPage(c, 1, 200, 20)
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ resp, errWithCode := m.processor.Admin().DomainPermissionExcludesGet(
+ c.Request.Context(),
+ c.Query(apiutil.DomainPermissionDomainKey),
+ page,
+ )
+ if errWithCode != nil {
+ apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
+ return
+ }
+
+ if resp.LinkHeader != "" {
+ c.Header("Link", resp.LinkHeader)
+ }
+
+ apiutil.JSON(c, http.StatusOK, resp.Items)
+}
diff --git a/internal/api/model/domain.go b/internal/api/model/domain.go
index ddc96ef05..c973c7d92 100644
--- a/internal/api/model/domain.go
+++ b/internal/api/model/domain.go
@@ -61,6 +61,9 @@ type DomainPermission struct {
// Time at which the permission entry was created (ISO 8601 Datetime).
// example: 2021-07-30T09:20:25+00:00
CreatedAt string `json:"created_at,omitempty"`
+ // Permission type of this entry (block, allow).
+ // Only set for domain permission drafts.
+ PermissionType string `json:"permission_type,omitempty"`
}
// DomainPermissionRequest is the form submitted as a POST to create a new domain permission entry (allow/block).
@@ -69,22 +72,24 @@ type DomainPermission struct {
type DomainPermissionRequest struct {
// A list of domains for which this permission request should apply.
// Only used if import=true is specified.
- Domains *multipart.FileHeader `form:"domains" json:"domains" xml:"domains"`
+ Domains *multipart.FileHeader `form:"domains" json:"domains"`
// A single domain for which this permission request should apply.
// Only used if import=true is NOT specified or if import=false.
// example: example.org
- Domain string `form:"domain" json:"domain" xml:"domain"`
+ Domain string `form:"domain" json:"domain"`
// Obfuscate the domain name when displaying this permission entry publicly.
// Ie., instead of 'example.org' show something like 'e**mpl*.or*'.
// example: false
- Obfuscate bool `form:"obfuscate" json:"obfuscate" xml:"obfuscate"`
+ Obfuscate bool `form:"obfuscate" json:"obfuscate"`
// Private comment for other admins on why this permission entry was created.
// example: don't like 'em!!!!
- PrivateComment string `form:"private_comment" json:"private_comment" xml:"private_comment"`
+ PrivateComment string `form:"private_comment" json:"private_comment"`
// Public comment on why this permission entry was created.
// Will be visible to requesters at /api/v1/instance/peers if this endpoint is exposed.
// example: foss dorks 😫
- PublicComment string `form:"public_comment" json:"public_comment" xml:"public_comment"`
+ PublicComment string `form:"public_comment" json:"public_comment"`
+ // Permission type to create (only applies to domain permission drafts, not explicit blocks and allows).
+ PermissionType string `form:"permission_type" json:"permission_type"`
}
// DomainKeysExpireRequest is the form submitted as a POST to /api/v1/admin/domain_keys_expire to expire a domain's public keys.
@@ -92,5 +97,5 @@ type DomainPermissionRequest struct {
// swagger:parameters domainKeysExpire
type DomainKeysExpireRequest struct {
// hostname/domain to expire keys for.
- Domain string `form:"domain" json:"domain" xml:"domain"`
+ Domain string `form:"domain" json:"domain"`
}
diff --git a/internal/api/util/parsequery.go b/internal/api/util/parsequery.go
index 024ec028b..9f4c02aed 100644
--- a/internal/api/util/parsequery.go
+++ b/internal/api/util/parsequery.go
@@ -69,8 +69,11 @@ const (
/* Domain permission keys */
- DomainPermissionExportKey = "export"
- DomainPermissionImportKey = "import"
+ DomainPermissionExportKey = "export"
+ DomainPermissionImportKey = "import"
+ DomainPermissionSubscriptionIDKey = "subscription_id"
+ DomainPermissionPermTypeKey = "permission_type"
+ DomainPermissionDomainKey = "domain"
/* Admin query keys */