[feature] Add domain limit DB model and API endpoints (#4554)
# Description > If this is a code change, please include a summary of what you've coded, and link to the issue(s) it closes/implements. > > If this is a documentation change, please briefly describe what you've changed and why. This pull request adds database models, (support) functions, migration, and API models + endpoints for upcoming domain limit functionality. Part of https://codeberg.org/superseriousbusiness/gotosocial/issues/2676, https://codeberg.org/superseriousbusiness/gotosocial/issues/9, and https://codeberg.org/superseriousbusiness/gotosocial/issues/1730 ## Checklist Please put an x inside each checkbox to indicate that you've read and followed it: `[ ]` -> `[x]` If this is a documentation change, only the first checkbox must be filled (you can delete the others if you want). - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [x] I/we have made any necessary changes to documentation. - [x] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4554 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
This commit is contained in:
@@ -36,6 +36,8 @@ const (
|
||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
||||
DomainAllowsPath = BasePath + "/domain_allows"
|
||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
||||
DomainLimitsPath = BasePath + "/domain_limits"
|
||||
DomainLimitsPathWithID = DomainLimitsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftsPath = BasePath + "/domain_permission_drafts"
|
||||
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
||||
@@ -112,6 +114,12 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
||||
attachHandler(http.MethodPut, DomainAllowsPathWithID, m.DomainAllowUpdatePUTHandler)
|
||||
attachHandler(http.MethodDelete, DomainAllowsPathWithID, m.DomainAllowDELETEHandler)
|
||||
|
||||
// domain limits stuff
|
||||
attachHandler(http.MethodGet, DomainLimitsPath, m.DomainLimitsGETHandler)
|
||||
attachHandler(http.MethodPost, DomainLimitsPath, m.DomainLimitsPOSTHandler)
|
||||
attachHandler(http.MethodPut, DomainLimitsPathWithID, m.DomainLimitPUTHandler)
|
||||
attachHandler(http.MethodDelete, DomainLimitsPathWithID, m.DomainLimitDELETEHandler)
|
||||
|
||||
// domain permission draft stuff
|
||||
attachHandler(http.MethodPost, DomainPermissionDraftsPath, m.DomainPermissionDraftsPOSTHandler)
|
||||
attachHandler(http.MethodGet, DomainPermissionDraftsPath, m.DomainPermissionDraftsGETHandler)
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
// 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"
|
||||
|
||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DomainLimitsPOSTHandler swagger:operation POST /api/v1/admin/domain_limits domainLimitCreate
|
||||
//
|
||||
// Create a domain limit.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// consumes:
|
||||
// - multipart/form-data
|
||||
// - application/json
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: domain
|
||||
// in: formData
|
||||
// description: Hostname of the domain to limit.
|
||||
// type: string
|
||||
// required: true
|
||||
// -
|
||||
// name: media_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to media files originating from the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Mark sensitive = mark all media from the limited domain as sensitive.
|
||||
// Reject = do not download media from the limited domain. Serve a link to the media instead.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - mark_sensitive
|
||||
// - reject
|
||||
// default: no_action
|
||||
// -
|
||||
// name: follows_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to follow (requests) originating from the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Manual approval = require manual approval for all follows from limited domain.
|
||||
// Reject non mutual = automatically reject follows from the limited domain when they're not follow-backs.
|
||||
// Reject all = automatically reject all follows from the limited domain.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - manual_approval
|
||||
// - reject_non_mutual
|
||||
// - reject_all
|
||||
// default: no_action
|
||||
// -
|
||||
// name: statuses_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to statuses of non-followed accounts on the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Filter warn = trigger a warn filter pointing to this domain limit.
|
||||
// Filter hide = trigger a hide filter pointing to this domain limit.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - filter_warn
|
||||
// - filter_hide
|
||||
// default: no_action
|
||||
// -
|
||||
// name: accounts_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to non-followed accounts on the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Mute = mute all non-followed accounts on the limited domain.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - mute
|
||||
// default: no_action
|
||||
// -
|
||||
// name: content_warning
|
||||
// in: formData
|
||||
// description: Content warning to prepend to posts from accounts on this instance.
|
||||
// type: string
|
||||
// -
|
||||
// name: public_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Public comment about this domain limit.
|
||||
// This will be displayed alongside the domain limit if you choose to share limits.
|
||||
// type: string
|
||||
// -
|
||||
// name: private_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Private comment about this domain limit. Will only be shown to other admins, so this
|
||||
// is a useful way of internally keeping track of why a certain domain ended up limited.
|
||||
// type: string
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin:write:domain_limits
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: The newly created domain limit.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainLimit"
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '403':
|
||||
// description: forbidden
|
||||
// '404':
|
||||
// description: not found
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '409':
|
||||
// description: There is already a limit in place for this domain.
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) DomainLimitsPOSTHandler(c *gin.Context) {
|
||||
authed, errWithCode := apiutil.TokenAuth(c,
|
||||
true, true, true, true,
|
||||
apiutil.ScopeAdminWriteDomainLimits,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, 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
|
||||
}
|
||||
|
||||
form := new(apimodel.DomainLimitRequest)
|
||||
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
|
||||
}
|
||||
|
||||
domainLimit, errWithCode := m.processor.Admin().DomainLimitCreate(
|
||||
c.Request.Context(),
|
||||
authed.Account,
|
||||
form.Domain,
|
||||
util.PtrOrValue(form.MediaPolicy, apimodel.MediaPolicyNoAction),
|
||||
util.PtrOrValue(form.FollowsPolicy, apimodel.FollowsPolicyNoAction),
|
||||
util.PtrOrValue(form.StatusesPolicy, apimodel.StatusesPolicyNoAction),
|
||||
util.PtrOrValue(form.AccountsPolicy, apimodel.AccountsPolicyNoAction),
|
||||
util.PtrOrZero(form.ContentWarning),
|
||||
util.PtrOrZero(form.PublicComment),
|
||||
util.PtrOrZero(form.PrivateComment),
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, domainLimit)
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// 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"
|
||||
|
||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DomainLimitDELETEHandler swagger:operation DELETE /api/v1/admin/domain_limits/{id} domainLimitDelete
|
||||
//
|
||||
// Delete domain limit with the given ID.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: id
|
||||
// type: string
|
||||
// description: The id of the domain limit.
|
||||
// in: path
|
||||
// required: true
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin:write:domain_limits
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: The domain limit that was just deleted.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainLimit"
|
||||
// '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) DomainLimitDELETEHandler(c *gin.Context) {
|
||||
authed, errWithCode := apiutil.TokenAuth(c,
|
||||
true, true, true, true,
|
||||
apiutil.ScopeAdminWriteDomainLimits,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, 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
|
||||
}
|
||||
|
||||
domainLimit, errWithCode := m.processor.Admin().DomainLimitDelete(
|
||||
c.Request.Context(),
|
||||
id,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, domainLimit)
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/paging"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DomainLimitsGETHandler swagger:operation GET /api/v1/admin/domain_limits domainLimitsGet
|
||||
//
|
||||
// View domain limits currently in place.
|
||||
//
|
||||
// By default, items will be returned in alphabetical order by domain.
|
||||
//
|
||||
// Paging is optional for this endpoint. To page, use the `limit`, `max_id` and/or `min_id` params. Else, all items will be returned.
|
||||
//
|
||||
// If paging, the next and previous queries can be parsed from the returned Link header.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ```
|
||||
// <https://example.org/api/v1/admin/domain_limits?limit=20&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/admin/domain_limits?limit=20&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
// ````
|
||||
//
|
||||
// If paging, items will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer).
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// 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. Use 0 to return all (no paging).
|
||||
// default: 20
|
||||
// minimum: 0
|
||||
// maximum: 100
|
||||
// in: query
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin:read:domain_limits
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Domain limits.
|
||||
// schema:
|
||||
// type: array
|
||||
// items:
|
||||
// "$ref": "#/definitions/domainLimit"
|
||||
// headers:
|
||||
// Link:
|
||||
// type: string
|
||||
// description: Links to the next and previous queries. Omitted if empty page or not paging.
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '403':
|
||||
// description: forbidden
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) DomainLimitsGETHandler(c *gin.Context) {
|
||||
authed, errWithCode := apiutil.TokenAuth(c,
|
||||
true, true, true, true,
|
||||
apiutil.ScopeAdminReadDomainLimits,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, 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
|
||||
}
|
||||
|
||||
// Allow paging but don't
|
||||
// enforce or use it by default.
|
||||
page, errWithCode := paging.ParseIDPage(c,
|
||||
0, // min items
|
||||
100, // max items
|
||||
0, // default (no paging)
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.Admin().DomainLimitsGet(
|
||||
c.Request.Context(),
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
// 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"
|
||||
|
||||
apimodel "code.superseriousbusiness.org/gotosocial/internal/api/model"
|
||||
apiutil "code.superseriousbusiness.org/gotosocial/internal/api/util"
|
||||
"code.superseriousbusiness.org/gotosocial/internal/gtserror"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DomainLimitUpdatePUTHandler swagger:operation PUT /api/v1/admin/domain_limits/{id} domainLimitUpdate
|
||||
//
|
||||
// Update a domain limit.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// consumes:
|
||||
// - multipart/form-data
|
||||
// - application/json
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: id
|
||||
// type: string
|
||||
// description: The id of the domain limit.
|
||||
// in: path
|
||||
// required: true
|
||||
// -
|
||||
// name: media_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to media files originating from the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Mark sensitive = mark all media from the limited domain as sensitive.
|
||||
// Reject = do not download media from the limited domain. Serve a link to the media instead.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - mark_sensitive
|
||||
// - reject
|
||||
// -
|
||||
// name: follows_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to follow (requests) originating from the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Manual approval = require manual approval for all follows from limited domain.
|
||||
// Reject non mutual = automatically reject follows from the limited domain when they're not follow-backs.
|
||||
// Reject all = automatically reject all follows from the limited domain.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - manual_approval
|
||||
// - reject_non_mutual
|
||||
// - reject_all
|
||||
// -
|
||||
// name: statuses_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to statuses of non-followed accounts on the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Filter warn = trigger a warn filter pointing to this domain limit.
|
||||
// Filter hide = trigger a hide filter pointing to this domain limit.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - filter_warn
|
||||
// - filter_hide
|
||||
// -
|
||||
// name: accounts_policy
|
||||
// in: formData
|
||||
// description: |-
|
||||
// Policy to apply to non-followed accounts on the limited domain.
|
||||
// No action = default (not limited).
|
||||
// Mute = mute all non-followed accounts on the limited domain.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
// enum:
|
||||
// - no_action
|
||||
// - mute
|
||||
// default: no_action
|
||||
// -
|
||||
// name: content_warning
|
||||
// in: formData
|
||||
// description: Content warning to prepend to posts from accounts on this instance. Omit to keep current value.
|
||||
// type: string
|
||||
// -
|
||||
// name: public_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Public comment about this domain limit.
|
||||
// This will be displayed alongside the domain limit if you choose to share limits.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
// -
|
||||
// name: private_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Private comment about this domain limit. Will only be shown to other admins, so this
|
||||
// is a useful way of internally keeping track of why a certain domain ended up limited.
|
||||
// Omit to keep current value.
|
||||
// type: string
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin:write:domain_limits
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: The updated domain limit.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainLimit"
|
||||
// '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) DomainLimitPUTHandler(c *gin.Context) {
|
||||
authed, errWithCode := apiutil.TokenAuth(c,
|
||||
true, true, true, true,
|
||||
apiutil.ScopeAdminWriteDomainLimits,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, 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
|
||||
}
|
||||
|
||||
form := new(apimodel.DomainLimitRequest)
|
||||
if err := c.ShouldBind(form); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure something is set to update.
|
||||
if form.MediaPolicy == nil &&
|
||||
form.FollowsPolicy == nil &&
|
||||
form.StatusesPolicy == nil &&
|
||||
form.AccountsPolicy == nil &&
|
||||
form.ContentWarning == nil &&
|
||||
form.PublicComment == nil &&
|
||||
form.PrivateComment == nil {
|
||||
const text = "nothing to update; at least one of media_policy, follows_policy, statuses_policy, accounts_policy, content_warning, public_comment, or private_comment must be set"
|
||||
errWithCode := gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
domainLimit, errWithCode := m.processor.Admin().DomainLimitUpdate(
|
||||
c.Request.Context(),
|
||||
id,
|
||||
form.MediaPolicy,
|
||||
form.FollowsPolicy,
|
||||
form.StatusesPolicy,
|
||||
form.AccountsPolicy,
|
||||
form.ContentWarning,
|
||||
form.PublicComment,
|
||||
form.PrivateComment,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, domainLimit)
|
||||
}
|
||||
Reference in New Issue
Block a user