mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-22 03:36:39 +00:00
Compare commits
2 commits
61395a9f5a
...
4f8542914e
Author | SHA1 | Date | |
---|---|---|---|
4f8542914e | |||
d2820a1470 |
2
go.mod
2
go.mod
|
@ -42,7 +42,7 @@ require (
|
||||||
github.com/k3a/html2text v1.2.1
|
github.com/k3a/html2text v1.2.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/miekg/dns v1.1.62
|
github.com/miekg/dns v1.1.62
|
||||||
github.com/minio/minio-go/v7 v7.0.79
|
github.com/minio/minio-go/v7 v7.0.80
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/ncruces/go-sqlite3 v0.20.0
|
github.com/ncruces/go-sqlite3 v0.20.0
|
||||||
github.com/oklog/ulid v1.3.1
|
github.com/oklog/ulid v1.3.1
|
||||||
|
|
4
go.sum
generated
4
go.sum
generated
|
@ -413,8 +413,8 @@ github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||||
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
|
||||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
github.com/minio/minio-go/v7 v7.0.79 h1:SvJZpj3hT0RN+4KiuX/FxLfPZdsuegy6d/2PiemM/bM=
|
github.com/minio/minio-go/v7 v7.0.80 h1:2mdUHXEykRdY/BigLt3Iuu1otL0JTogT0Nmltg0wujk=
|
||||||
github.com/minio/minio-go/v7 v7.0.79/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0=
|
github.com/minio/minio-go/v7 v7.0.80/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0=
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
||||||
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
||||||
DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
|
DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
|
||||||
|
DomainPermissionExcludesPath = BasePath + "/domain_permission_excludes"
|
||||||
|
DomainPermissionExcludesPathWithID = DomainPermissionExcludesPath + "/:" + apiutil.IDKey
|
||||||
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
||||||
HeaderAllowsPath = BasePath + "/header_allows"
|
HeaderAllowsPath = BasePath + "/header_allows"
|
||||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
||||||
|
@ -110,6 +112,12 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
||||||
attachHandler(http.MethodPost, DomainPermissionDraftAcceptPath, m.DomainPermissionDraftAcceptPOSTHandler)
|
attachHandler(http.MethodPost, DomainPermissionDraftAcceptPath, m.DomainPermissionDraftAcceptPOSTHandler)
|
||||||
attachHandler(http.MethodPost, DomainPermissionDraftRemovePath, m.DomainPermissionDraftRemovePOSTHandler)
|
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
|
// header filtering administration routes
|
||||||
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
|
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
|
||||||
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
|
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
|
||||||
|
|
|
@ -50,11 +50,11 @@
|
||||||
// description: ID of the domain permission draft.
|
// description: ID of the domain permission draft.
|
||||||
// type: string
|
// type: string
|
||||||
// -
|
// -
|
||||||
// name: ignore_target
|
// name: exclude_target
|
||||||
// in: formData
|
// in: formData
|
||||||
// description: >-
|
// description: >-
|
||||||
// When removing the domain permission draft, also create a
|
// When removing the domain permission draft, also create a
|
||||||
// domain ignore entry for the target domain, so that drafts
|
// domain exclude entry for the target domain, so that drafts
|
||||||
// will not be created for this domain in the future.
|
// will not be created for this domain in the future.
|
||||||
// type: boolean
|
// type: boolean
|
||||||
// default: false
|
// default: false
|
||||||
|
@ -110,7 +110,7 @@ func (m *Module) DomainPermissionDraftRemovePOSTHandler(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RemoveForm struct {
|
type RemoveForm struct {
|
||||||
IgnoreTarget bool `json:"ignore_target" form:"ignore_target"`
|
ExcludeTarget bool `json:"exclude_target" form:"exclude_target"`
|
||||||
}
|
}
|
||||||
|
|
||||||
form := new(RemoveForm)
|
form := new(RemoveForm)
|
||||||
|
@ -123,7 +123,7 @@ type RemoveForm struct {
|
||||||
c.Request.Context(),
|
c.Request.Context(),
|
||||||
authed.Account,
|
authed.Account,
|
||||||
id,
|
id,
|
||||||
form.IgnoreTarget,
|
form.ExcludeTarget,
|
||||||
)
|
)
|
||||||
if errWithCode != nil {
|
if errWithCode != nil {
|
||||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
|
|
104
internal/api/client/admin/domainpermissionexclude.go
Normal file
104
internal/api/client/admin/domainpermissionexclude.go
Normal file
|
@ -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)
|
||||||
|
}
|
138
internal/api/client/admin/domainpermissionexcludecreate.go
Normal file
138
internal/api/client/admin/domainpermissionexcludecreate.go
Normal file
|
@ -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)
|
||||||
|
}
|
110
internal/api/client/admin/domainpermissionexcluderemove.go
Normal file
110
internal/api/client/admin/domainpermissionexcluderemove.go
Normal file
|
@ -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)
|
||||||
|
}
|
159
internal/api/client/admin/domainpermissionexcludes.go
Normal file
159
internal/api/client/admin/domainpermissionexcludes.go
Normal file
|
@ -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)
|
||||||
|
}
|
2
internal/cache/cache.go
vendored
2
internal/cache/cache.go
vendored
|
@ -76,7 +76,7 @@ func (c *Caches) Init() {
|
||||||
c.initDomainBlock()
|
c.initDomainBlock()
|
||||||
c.initDomainPermissionDraft()
|
c.initDomainPermissionDraft()
|
||||||
c.initDomainPermissionSubscription()
|
c.initDomainPermissionSubscription()
|
||||||
c.initDomainPermissionIgnore()
|
c.initDomainPermissionExclude()
|
||||||
c.initEmoji()
|
c.initEmoji()
|
||||||
c.initEmojiCategory()
|
c.initEmojiCategory()
|
||||||
c.initFilter()
|
c.initFilter()
|
||||||
|
|
8
internal/cache/db.go
vendored
8
internal/cache/db.go
vendored
|
@ -73,8 +73,8 @@ type DBCaches struct {
|
||||||
// DomainPermissionSubscription provides access to the domain permission subscription database cache.
|
// DomainPermissionSubscription provides access to the domain permission subscription database cache.
|
||||||
DomainPermissionSubscription StructCache[*gtsmodel.DomainPermissionSubscription]
|
DomainPermissionSubscription StructCache[*gtsmodel.DomainPermissionSubscription]
|
||||||
|
|
||||||
// DomainPermissionIgnore provides access to the domain permission ignore database cache.
|
// DomainPermissionExclude provides access to the domain permission exclude database cache.
|
||||||
DomainPermissionIgnore *domain.Cache
|
DomainPermissionExclude *domain.Cache
|
||||||
|
|
||||||
// Emoji provides access to the gtsmodel Emoji database cache.
|
// Emoji provides access to the gtsmodel Emoji database cache.
|
||||||
Emoji StructCache[*gtsmodel.Emoji]
|
Emoji StructCache[*gtsmodel.Emoji]
|
||||||
|
@ -620,8 +620,8 @@ func (c *Caches) initDomainPermissionSubscription() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Caches) initDomainPermissionIgnore() {
|
func (c *Caches) initDomainPermissionExclude() {
|
||||||
c.DB.DomainPermissionIgnore = new(domain.Cache)
|
c.DB.DomainPermissionExclude = new(domain.Cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Caches) initEmoji() {
|
func (c *Caches) initEmoji() {
|
||||||
|
|
|
@ -34,31 +34,31 @@
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (d *domainDB) PutDomainPermissionIgnore(
|
func (d *domainDB) PutDomainPermissionExclude(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
ignore *gtsmodel.DomainPermissionIgnore,
|
exclude *gtsmodel.DomainPermissionExclude,
|
||||||
) error {
|
) error {
|
||||||
// Normalize the domain as punycode
|
// Normalize the domain as punycode
|
||||||
var err error
|
var err error
|
||||||
ignore.Domain, err = util.Punify(ignore.Domain)
|
exclude.Domain, err = util.Punify(exclude.Domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to store domain perm ignore in DB
|
// Attempt to store domain perm exclude in DB
|
||||||
if _, err := d.db.NewInsert().
|
if _, err := d.db.NewInsert().
|
||||||
Model(ignore).
|
Model(exclude).
|
||||||
Exec(ctx); err != nil {
|
Exec(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the domain perm ignore cache (for later reload)
|
// Clear the domain perm exclude cache (for later reload)
|
||||||
d.state.Caches.DB.DomainPermissionIgnore.Clear()
|
d.state.Caches.DB.DomainPermissionExclude.Clear()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *domainDB) IsDomainPermissionIgnored(ctx context.Context, domain string) (bool, error) {
|
func (d *domainDB) IsDomainPermissionExcluded(ctx context.Context, domain string) (bool, error) {
|
||||||
// Normalize the domain as punycode
|
// Normalize the domain as punycode
|
||||||
domain, err := util.Punify(domain)
|
domain, err := util.Punify(domain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -67,20 +67,20 @@ func (d *domainDB) IsDomainPermissionIgnored(ctx context.Context, domain string)
|
||||||
|
|
||||||
// Check if our host and given domain are equal
|
// Check if our host and given domain are equal
|
||||||
// or part of the same second-level domain; we
|
// or part of the same second-level domain; we
|
||||||
// always ignore such perms as creating blocks
|
// always exclude such perms as creating blocks
|
||||||
// or allows in such cases may break things.
|
// or allows in such cases may break things.
|
||||||
if dns.CompareDomainName(domain, config.GetHost()) >= 2 {
|
if dns.CompareDomainName(domain, config.GetHost()) >= 2 {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Func to scan list of all
|
// Func to scan list of all
|
||||||
// ignored domain perms from DB.
|
// excluded domain perms from DB.
|
||||||
loadF := func() ([]string, error) {
|
loadF := func() ([]string, error) {
|
||||||
var domains []string
|
var domains []string
|
||||||
|
|
||||||
if err := d.db.
|
if err := d.db.
|
||||||
NewSelect().
|
NewSelect().
|
||||||
Table("domain_ignores").
|
Table("domain_excludes").
|
||||||
Column("domain").
|
Column("domain").
|
||||||
Scan(ctx, &domains); err != nil {
|
Scan(ctx, &domains); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -89,51 +89,51 @@ func (d *domainDB) IsDomainPermissionIgnored(ctx context.Context, domain string)
|
||||||
return domains, nil
|
return domains, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the cache for a domain perm ignore,
|
// Check the cache for a domain perm exclude,
|
||||||
// hydrating the cache with loadF if necessary.
|
// hydrating the cache with loadF if necessary.
|
||||||
return d.state.Caches.DB.DomainPermissionIgnore.Matches(domain, loadF)
|
return d.state.Caches.DB.DomainPermissionExclude.Matches(domain, loadF)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *domainDB) GetDomainPermissionIgnoreByID(
|
func (d *domainDB) GetDomainPermissionExcludeByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
id string,
|
id string,
|
||||||
) (*gtsmodel.DomainPermissionIgnore, error) {
|
) (*gtsmodel.DomainPermissionExclude, error) {
|
||||||
ignore := new(gtsmodel.DomainPermissionIgnore)
|
exclude := new(gtsmodel.DomainPermissionExclude)
|
||||||
|
|
||||||
q := d.db.
|
q := d.db.
|
||||||
NewSelect().
|
NewSelect().
|
||||||
Model(ignore).
|
Model(exclude).
|
||||||
Where("? = ?", bun.Ident("domain_permission_ignore.id"), id)
|
Where("? = ?", bun.Ident("domain_permission_exclude.id"), id)
|
||||||
if err := q.Scan(ctx); err != nil {
|
if err := q.Scan(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if gtscontext.Barebones(ctx) {
|
if gtscontext.Barebones(ctx) {
|
||||||
// No need to fully populate.
|
// No need to fully populate.
|
||||||
return ignore, nil
|
return exclude, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if ignore.CreatedByAccount == nil {
|
if exclude.CreatedByAccount == nil {
|
||||||
// Not set, fetch from database.
|
// Not set, fetch from database.
|
||||||
var err error
|
var err error
|
||||||
ignore.CreatedByAccount, err = d.state.DB.GetAccountByID(
|
exclude.CreatedByAccount, err = d.state.DB.GetAccountByID(
|
||||||
gtscontext.SetBarebones(ctx),
|
gtscontext.SetBarebones(ctx),
|
||||||
ignore.CreatedByAccountID,
|
exclude.CreatedByAccountID,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.Newf("error populating created by account: %w", err)
|
return nil, gtserror.Newf("error populating created by account: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ignore, nil
|
return exclude, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *domainDB) GetDomainPermissionIgnores(
|
func (d *domainDB) GetDomainPermissionExcludes(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
domain string,
|
domain string,
|
||||||
page *paging.Page,
|
page *paging.Page,
|
||||||
) (
|
) (
|
||||||
[]*gtsmodel.DomainPermissionIgnore,
|
[]*gtsmodel.DomainPermissionExclude,
|
||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
var (
|
var (
|
||||||
|
@ -144,25 +144,25 @@ func (d *domainDB) GetDomainPermissionIgnores(
|
||||||
order = page.GetOrder()
|
order = page.GetOrder()
|
||||||
|
|
||||||
// Make educated guess for slice size
|
// Make educated guess for slice size
|
||||||
ignoreIDs = make([]string, 0, limit)
|
excludeIDs = make([]string, 0, limit)
|
||||||
)
|
)
|
||||||
|
|
||||||
q := d.db.
|
q := d.db.
|
||||||
NewSelect().
|
NewSelect().
|
||||||
TableExpr(
|
TableExpr(
|
||||||
"? AS ?",
|
"? AS ?",
|
||||||
bun.Ident("domain_permission_ignores"),
|
bun.Ident("domain_permission_excludes"),
|
||||||
bun.Ident("domain_permission_ignore"),
|
bun.Ident("domain_permission_exclude"),
|
||||||
).
|
).
|
||||||
// Select only IDs from table
|
// Select only IDs from table
|
||||||
Column("domain_permission_ignore.id")
|
Column("domain_permission_exclude.id")
|
||||||
|
|
||||||
// Return only items with id
|
// Return only items with id
|
||||||
// lower than provided maxID.
|
// lower than provided maxID.
|
||||||
if maxID != "" {
|
if maxID != "" {
|
||||||
q = q.Where(
|
q = q.Where(
|
||||||
"? < ?",
|
"? < ?",
|
||||||
bun.Ident("domain_permission_ignore.id"),
|
bun.Ident("domain_permission_exclude.id"),
|
||||||
maxID,
|
maxID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ func (d *domainDB) GetDomainPermissionIgnores(
|
||||||
if minID != "" {
|
if minID != "" {
|
||||||
q = q.Where(
|
q = q.Where(
|
||||||
"? > ?",
|
"? > ?",
|
||||||
bun.Ident("domain_permission_ignore.id"),
|
bun.Ident("domain_permission_exclude.id"),
|
||||||
minID,
|
minID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -190,7 +190,7 @@ func (d *domainDB) GetDomainPermissionIgnores(
|
||||||
|
|
||||||
q = q.Where(
|
q = q.Where(
|
||||||
"? = ?",
|
"? = ?",
|
||||||
bun.Ident("domain_permission_ignore.domain"),
|
bun.Ident("domain_permission_exclude.domain"),
|
||||||
domain,
|
domain,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -205,48 +205,48 @@ func (d *domainDB) GetDomainPermissionIgnores(
|
||||||
// Page up.
|
// Page up.
|
||||||
q = q.OrderExpr(
|
q = q.OrderExpr(
|
||||||
"? ASC",
|
"? ASC",
|
||||||
bun.Ident("domain_permission_ignore.id"),
|
bun.Ident("domain_permission_exclude.id"),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// Page down.
|
// Page down.
|
||||||
q = q.OrderExpr(
|
q = q.OrderExpr(
|
||||||
"? DESC",
|
"? DESC",
|
||||||
bun.Ident("domain_permission_ignore.id"),
|
bun.Ident("domain_permission_exclude.id"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := q.Scan(ctx, &ignoreIDs); err != nil {
|
if err := q.Scan(ctx, &excludeIDs); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch case of no items early
|
// Catch case of no items early
|
||||||
if len(ignoreIDs) == 0 {
|
if len(excludeIDs) == 0 {
|
||||||
return nil, db.ErrNoEntries
|
return nil, db.ErrNoEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're paging up, we still want items
|
// If we're paging up, we still want items
|
||||||
// to be sorted by ID desc, so reverse slice.
|
// to be sorted by ID desc, so reverse slice.
|
||||||
if order == paging.OrderAscending {
|
if order == paging.OrderAscending {
|
||||||
slices.Reverse(ignoreIDs)
|
slices.Reverse(excludeIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate return slice (will be at most len permSubIDs).
|
// Allocate return slice (will be at most len permSubIDs).
|
||||||
ignores := make([]*gtsmodel.DomainPermissionIgnore, 0, len(ignoreIDs))
|
excludes := make([]*gtsmodel.DomainPermissionExclude, 0, len(excludeIDs))
|
||||||
for _, id := range ignoreIDs {
|
for _, id := range excludeIDs {
|
||||||
ignore, err := d.GetDomainPermissionIgnoreByID(ctx, id)
|
exclude, err := d.GetDomainPermissionExcludeByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf(ctx, "error getting domain permission ignore %q: %v", id, err)
|
log.Errorf(ctx, "error getting domain permission exclude %q: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append to return slice
|
// Append to return slice
|
||||||
ignores = append(ignores, ignore)
|
excludes = append(excludes, exclude)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ignores, nil
|
return excludes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *domainDB) DeleteDomainPermissionIgnore(
|
func (d *domainDB) DeleteDomainPermissionExclude(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
id string,
|
id string,
|
||||||
) error {
|
) error {
|
||||||
|
@ -254,12 +254,12 @@ func (d *domainDB) DeleteDomainPermissionIgnore(
|
||||||
q := d.db.NewDelete().
|
q := d.db.NewDelete().
|
||||||
TableExpr(
|
TableExpr(
|
||||||
"? AS ?",
|
"? AS ?",
|
||||||
bun.Ident("domain_permission_ignores"),
|
bun.Ident("domain_permission_excludes"),
|
||||||
bun.Ident("domain_permission_ignore"),
|
bun.Ident("domain_permission_exclude"),
|
||||||
).
|
).
|
||||||
Where(
|
Where(
|
||||||
"? = ?",
|
"? = ?",
|
||||||
bun.Ident("domain_permission_ignore.id"),
|
bun.Ident("domain_permission_exclude.id"),
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -268,8 +268,8 @@ func (d *domainDB) DeleteDomainPermissionIgnore(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the domain perm ignore cache (for later reload)
|
// Clear the domain perm exclude cache (for later reload)
|
||||||
d.state.Caches.DB.DomainPermissionIgnore.Clear()
|
d.state.Caches.DB.DomainPermissionExclude.Clear()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@ func init() {
|
||||||
// Create `domain_permission_ignores`.
|
// Create `domain_permission_ignores`.
|
||||||
if _, err := tx.
|
if _, err := tx.
|
||||||
NewCreateTable().
|
NewCreateTable().
|
||||||
Model((*gtsmodel.DomainPermissionIgnore)(nil)).
|
Model((*gtsmodel.DomainPermissionExclude)(nil)).
|
||||||
IfNotExists().
|
IfNotExists().
|
||||||
Exec(ctx); err != nil {
|
Exec(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -110,25 +110,25 @@ type Domain interface {
|
||||||
DeleteDomainPermissionDraft(ctx context.Context, id string) error
|
DeleteDomainPermissionDraft(ctx context.Context, id string) error
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Domain permission ignore stuff.
|
Domain permission exclude stuff.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// GetDomainPermissionIgnoreByID gets one DomainPermissionIgnore with the given ID.
|
// GetDomainPermissionExcludeByID gets one DomainPermissionExclude with the given ID.
|
||||||
GetDomainPermissionIgnoreByID(ctx context.Context, id string) (*gtsmodel.DomainPermissionIgnore, error)
|
GetDomainPermissionExcludeByID(ctx context.Context, id string) (*gtsmodel.DomainPermissionExclude, error)
|
||||||
|
|
||||||
// GetDomainPermissionIgnores returns a page of
|
// GetDomainPermissionExcludes returns a page of
|
||||||
// DomainPermissionIgnores using the given parameters.
|
// DomainPermissionExcludes using the given parameters.
|
||||||
GetDomainPermissionIgnores(
|
GetDomainPermissionExcludes(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
domain string,
|
domain string,
|
||||||
page *paging.Page,
|
page *paging.Page,
|
||||||
) ([]*gtsmodel.DomainPermissionIgnore, error)
|
) ([]*gtsmodel.DomainPermissionExclude, error)
|
||||||
|
|
||||||
// PutDomainPermissionIgnore stores one DomainPermissionIgnore.
|
// PutDomainPermissionExclude stores one DomainPermissionExclude.
|
||||||
PutDomainPermissionIgnore(ctx context.Context, permIgnore *gtsmodel.DomainPermissionIgnore) error
|
PutDomainPermissionExclude(ctx context.Context, permExclude *gtsmodel.DomainPermissionExclude) error
|
||||||
|
|
||||||
// DeleteDomainPermissionIgnore deletes one DomainPermissionIgnore with the given id.
|
// DeleteDomainPermissionExclude deletes one DomainPermissionExclude with the given id.
|
||||||
DeleteDomainPermissionIgnore(ctx context.Context, id string) error
|
DeleteDomainPermissionExclude(ctx context.Context, id string) error
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Domain permission subscription stuff.
|
Domain permission subscription stuff.
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// DomainPermission models a domain permission
|
// DomainPermission models a domain permission
|
||||||
// entry -- block / allow / draft / ignore.
|
// entry -- block / allow / draft / exclude.
|
||||||
type DomainPermission interface {
|
type DomainPermission interface {
|
||||||
GetID() string
|
GetID() string
|
||||||
GetCreatedAt() time.Time
|
GetCreatedAt() time.Time
|
||||||
|
|
|
@ -23,59 +23,59 @@
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DomainPermissionIgnore represents one domain that should be ignored
|
// DomainPermissionExclude represents one domain that should be excluded
|
||||||
// when domain permission (ignores) are created from subscriptions.
|
// when domain permission (excludes) are created from subscriptions.
|
||||||
type DomainPermissionIgnore struct {
|
type DomainPermissionExclude struct {
|
||||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // ID of this item in the database.
|
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // ID of this item in the database.
|
||||||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was created.
|
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was created.
|
||||||
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was last updated.
|
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was last updated.
|
||||||
Domain string `bun:",nullzero,notnull,unique"` // Domain to ignore. Eg. 'whatever.com'.
|
Domain string `bun:",nullzero,notnull,unique"` // Domain to exclude. Eg. 'whatever.com'.
|
||||||
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this ignore.
|
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this exclude.
|
||||||
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
||||||
PrivateComment string `bun:",nullzero"` // Private comment on this ignore, viewable to admins.
|
PrivateComment string `bun:",nullzero"` // Private comment on this exclude, viewable to admins.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetID() string {
|
func (d *DomainPermissionExclude) GetID() string {
|
||||||
return d.ID
|
return d.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetCreatedAt() time.Time {
|
func (d *DomainPermissionExclude) GetCreatedAt() time.Time {
|
||||||
return d.CreatedAt
|
return d.CreatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetUpdatedAt() time.Time {
|
func (d *DomainPermissionExclude) GetUpdatedAt() time.Time {
|
||||||
return d.UpdatedAt
|
return d.UpdatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) SetUpdatedAt(i time.Time) {
|
func (d *DomainPermissionExclude) SetUpdatedAt(i time.Time) {
|
||||||
d.UpdatedAt = i
|
d.UpdatedAt = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetDomain() string {
|
func (d *DomainPermissionExclude) GetDomain() string {
|
||||||
return d.Domain
|
return d.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetCreatedByAccountID() string {
|
func (d *DomainPermissionExclude) GetCreatedByAccountID() string {
|
||||||
return d.CreatedByAccountID
|
return d.CreatedByAccountID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) SetCreatedByAccountID(i string) {
|
func (d *DomainPermissionExclude) SetCreatedByAccountID(i string) {
|
||||||
d.CreatedByAccountID = i
|
d.CreatedByAccountID = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetCreatedByAccount() *Account {
|
func (d *DomainPermissionExclude) GetCreatedByAccount() *Account {
|
||||||
return d.CreatedByAccount
|
return d.CreatedByAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) SetCreatedByAccount(i *Account) {
|
func (d *DomainPermissionExclude) SetCreatedByAccount(i *Account) {
|
||||||
d.CreatedByAccount = i
|
d.CreatedByAccount = i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetPrivateComment() string {
|
func (d *DomainPermissionExclude) GetPrivateComment() string {
|
||||||
return d.PrivateComment
|
return d.PrivateComment
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) SetPrivateComment(i string) {
|
func (d *DomainPermissionExclude) SetPrivateComment(i string) {
|
||||||
d.PrivateComment = i
|
d.PrivateComment = i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,10 +83,10 @@ func (d *DomainPermissionIgnore) SetPrivateComment(i string) {
|
||||||
Stubbed functions for interface purposes.
|
Stubbed functions for interface purposes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (d *DomainPermissionIgnore) GetPublicComment() string { return "" }
|
func (d *DomainPermissionExclude) GetPublicComment() string { return "" }
|
||||||
func (d *DomainPermissionIgnore) SetPublicComment(_ string) {}
|
func (d *DomainPermissionExclude) SetPublicComment(_ string) {}
|
||||||
func (d *DomainPermissionIgnore) GetObfuscate() *bool { return util.Ptr(false) }
|
func (d *DomainPermissionExclude) GetObfuscate() *bool { return util.Ptr(false) }
|
||||||
func (d *DomainPermissionIgnore) SetObfuscate(_ *bool) {}
|
func (d *DomainPermissionExclude) SetObfuscate(_ *bool) {}
|
||||||
func (d *DomainPermissionIgnore) GetSubscriptionID() string { return "" }
|
func (d *DomainPermissionExclude) GetSubscriptionID() string { return "" }
|
||||||
func (d *DomainPermissionIgnore) SetSubscriptionID(_ string) {}
|
func (d *DomainPermissionExclude) SetSubscriptionID(_ string) {}
|
||||||
func (d *DomainPermissionIgnore) GetType() DomainPermissionType { return DomainPermissionUnknown }
|
func (d *DomainPermissionExclude) GetType() DomainPermissionType { return DomainPermissionUnknown }
|
|
@ -287,7 +287,7 @@ func (p *Processor) DomainPermissionDraftRemove(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
acct *gtsmodel.Account,
|
acct *gtsmodel.Account,
|
||||||
id string,
|
id string,
|
||||||
ignoreTarget bool,
|
excludeTarget bool,
|
||||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
|
@ -306,17 +306,17 @@ func (p *Processor) DomainPermissionDraftRemove(
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ignoreTarget {
|
if excludeTarget {
|
||||||
// Add a domain permission ignore
|
// Add a domain permission exclude
|
||||||
// targeting the permDraft's domain.
|
// targeting the permDraft's domain.
|
||||||
_, err = p.DomainPermissionIgnoreCreate(
|
_, err = p.DomainPermissionExcludeCreate(
|
||||||
ctx,
|
ctx,
|
||||||
acct,
|
acct,
|
||||||
permDraft.Domain,
|
permDraft.Domain,
|
||||||
permDraft.PrivateComment,
|
permDraft.PrivateComment,
|
||||||
)
|
)
|
||||||
if err != nil && !errors.Is(err, db.ErrAlreadyExists) {
|
if err != nil && !errors.Is(err, db.ErrAlreadyExists) {
|
||||||
err := gtserror.Newf("db error creating domain permission ignore: %w", err)
|
err := gtserror.Newf("db error creating domain permission exclude: %w", err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,13 +32,13 @@
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Processor) DomainPermissionIgnoreCreate(
|
func (p *Processor) DomainPermissionExcludeCreate(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
acct *gtsmodel.Account,
|
acct *gtsmodel.Account,
|
||||||
domain string,
|
domain string,
|
||||||
privateComment string,
|
privateComment string,
|
||||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
permIgnore := >smodel.DomainPermissionIgnore{
|
permExclude := >smodel.DomainPermissionExclude{
|
||||||
ID: id.NewULID(),
|
ID: id.NewULID(),
|
||||||
Domain: domain,
|
Domain: domain,
|
||||||
CreatedByAccountID: acct.ID,
|
CreatedByAccountID: acct.ID,
|
||||||
|
@ -46,49 +46,49 @@ func (p *Processor) DomainPermissionIgnoreCreate(
|
||||||
PrivateComment: privateComment,
|
PrivateComment: privateComment,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.state.DB.PutDomainPermissionIgnore(ctx, permIgnore); err != nil {
|
if err := p.state.DB.PutDomainPermissionExclude(ctx, permExclude); err != nil {
|
||||||
if errors.Is(err, db.ErrAlreadyExists) {
|
if errors.Is(err, db.ErrAlreadyExists) {
|
||||||
const text = "a domain permission ignore already exists with this permission type and domain"
|
const text = "a domain permission exclude already exists with this permission type and domain"
|
||||||
err := fmt.Errorf("%w: %s", err, text)
|
err := fmt.Errorf("%w: %s", err, text)
|
||||||
return nil, gtserror.NewErrorConflict(err, text)
|
return nil, gtserror.NewErrorConflict(err, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Real error.
|
// Real error.
|
||||||
err := gtserror.Newf("db error putting domain permission ignore: %w", err)
|
err := gtserror.Newf("db error putting domain permission exclude: %w", err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.apiDomainPerm(ctx, permIgnore, false)
|
return p.apiDomainPerm(ctx, permExclude, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainPermissionIgnoreGet returns one
|
// DomainPermissionExcludeGet returns one
|
||||||
// domain permission ignore with the given id.
|
// domain permission exclude with the given id.
|
||||||
func (p *Processor) DomainPermissionIgnoreGet(
|
func (p *Processor) DomainPermissionExcludeGet(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
id string,
|
id string,
|
||||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
permIgnore, err := p.state.DB.GetDomainPermissionIgnoreByID(ctx, id)
|
permExclude, err := p.state.DB.GetDomainPermissionExcludeByID(ctx, id)
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
err := gtserror.Newf("db error getting domain permission ignore %s: %w", id, err)
|
err := gtserror.Newf("db error getting domain permission exclude %s: %w", id, err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if permIgnore == nil {
|
if permExclude == nil {
|
||||||
err := fmt.Errorf("domain permission ignore %s not found", id)
|
err := fmt.Errorf("domain permission exclude %s not found", id)
|
||||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.apiDomainPerm(ctx, permIgnore, false)
|
return p.apiDomainPerm(ctx, permExclude, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainPermissionIgnoresGet returns a page of
|
// DomainPermissionExcludesGet returns a page of
|
||||||
// DomainPermissionIgnores with the given parameters.
|
// DomainPermissionExcludes with the given parameters.
|
||||||
func (p *Processor) DomainPermissionIgnoresGet(
|
func (p *Processor) DomainPermissionExcludesGet(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
domain string,
|
domain string,
|
||||||
page *paging.Page,
|
page *paging.Page,
|
||||||
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||||
permIgnores, err := p.state.DB.GetDomainPermissionIgnores(
|
permExcludes, err := p.state.DB.GetDomainPermissionExcludes(
|
||||||
ctx,
|
ctx,
|
||||||
domain,
|
domain,
|
||||||
page,
|
page,
|
||||||
|
@ -98,24 +98,24 @@ func (p *Processor) DomainPermissionIgnoresGet(
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
count := len(permIgnores)
|
count := len(permExcludes)
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return paging.EmptyResponse(), nil
|
return paging.EmptyResponse(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the lowest and highest
|
// Get the lowest and highest
|
||||||
// ID values, used for paging.
|
// ID values, used for paging.
|
||||||
lo := permIgnores[count-1].ID
|
lo := permExcludes[count-1].ID
|
||||||
hi := permIgnores[0].ID
|
hi := permExcludes[0].ID
|
||||||
|
|
||||||
// Convert each perm ignore to API model.
|
// Convert each perm exclude to API model.
|
||||||
items := make([]any, len(permIgnores))
|
items := make([]any, len(permExcludes))
|
||||||
for i, permIgnore := range permIgnores {
|
for i, permExclude := range permExcludes {
|
||||||
apiPermIgnore, err := p.apiDomainPerm(ctx, permIgnore, false)
|
apiPermExclude, err := p.apiDomainPerm(ctx, permExclude, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
items[i] = apiPermIgnore
|
items[i] = apiPermExclude
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble next/prev page queries.
|
// Assemble next/prev page queries.
|
||||||
|
@ -126,9 +126,34 @@ func (p *Processor) DomainPermissionIgnoresGet(
|
||||||
|
|
||||||
return paging.PackageResponse(paging.ResponseParams{
|
return paging.PackageResponse(paging.ResponseParams{
|
||||||
Items: items,
|
Items: items,
|
||||||
Path: "/api/v1/admin/domain_permission_ignores",
|
Path: "/api/v1/admin/domain_permission_excludes",
|
||||||
Next: page.Next(lo, hi),
|
Next: page.Next(lo, hi),
|
||||||
Prev: page.Prev(lo, hi),
|
Prev: page.Prev(lo, hi),
|
||||||
Query: query,
|
Query: query,
|
||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Processor) DomainPermissionExcludeRemove(
|
||||||
|
ctx context.Context,
|
||||||
|
acct *gtsmodel.Account,
|
||||||
|
id string,
|
||||||
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
|
permExclude, err := p.state.DB.GetDomainPermissionExcludeByID(ctx, id)
|
||||||
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
|
err := gtserror.Newf("db error getting domain permission exclude %s: %w", id, err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if permExclude == nil {
|
||||||
|
err := fmt.Errorf("domain permission exclude %s not found", id)
|
||||||
|
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the permission exclude.
|
||||||
|
if err := p.state.DB.DeleteDomainPermissionExclude(ctx, permExclude.ID); err != nil {
|
||||||
|
err := gtserror.Newf("db error deleting domain permission exclude: %w", err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.apiDomainPerm(ctx, permExclude, false)
|
||||||
|
}
|
14
vendor/github.com/minio/minio-go/v7/api.go
generated
vendored
14
vendor/github.com/minio/minio-go/v7/api.go
generated
vendored
|
@ -99,6 +99,7 @@ type Client struct {
|
||||||
healthStatus int32
|
healthStatus int32
|
||||||
|
|
||||||
trailingHeaderSupport bool
|
trailingHeaderSupport bool
|
||||||
|
maxRetries int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options for New method
|
// Options for New method
|
||||||
|
@ -123,12 +124,16 @@ type Options struct {
|
||||||
// Custom hash routines. Leave nil to use standard.
|
// Custom hash routines. Leave nil to use standard.
|
||||||
CustomMD5 func() md5simd.Hasher
|
CustomMD5 func() md5simd.Hasher
|
||||||
CustomSHA256 func() md5simd.Hasher
|
CustomSHA256 func() md5simd.Hasher
|
||||||
|
|
||||||
|
// Number of times a request is retried. Defaults to 10 retries if this option is not configured.
|
||||||
|
// Set to 1 to disable retries.
|
||||||
|
MaxRetries int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global constants.
|
// Global constants.
|
||||||
const (
|
const (
|
||||||
libraryName = "minio-go"
|
libraryName = "minio-go"
|
||||||
libraryVersion = "v7.0.79"
|
libraryVersion = "v7.0.80"
|
||||||
)
|
)
|
||||||
|
|
||||||
// User Agent should always following the below style.
|
// User Agent should always following the below style.
|
||||||
|
@ -278,6 +283,11 @@ func privateNew(endpoint string, opts *Options) (*Client, error) {
|
||||||
// healthcheck is not initialized
|
// healthcheck is not initialized
|
||||||
clnt.healthStatus = unknown
|
clnt.healthStatus = unknown
|
||||||
|
|
||||||
|
clnt.maxRetries = MaxRetry
|
||||||
|
if opts.MaxRetries > 0 {
|
||||||
|
clnt.maxRetries = opts.MaxRetries
|
||||||
|
}
|
||||||
|
|
||||||
// Return.
|
// Return.
|
||||||
return clnt, nil
|
return clnt, nil
|
||||||
}
|
}
|
||||||
|
@ -592,7 +602,7 @@ func (c *Client) executeMethod(ctx context.Context, method string, metadata requ
|
||||||
|
|
||||||
var retryable bool // Indicates if request can be retried.
|
var retryable bool // Indicates if request can be retried.
|
||||||
var bodySeeker io.Seeker // Extracted seeker from io.Reader.
|
var bodySeeker io.Seeker // Extracted seeker from io.Reader.
|
||||||
reqRetry := MaxRetry // Indicates how many times we can retry the request
|
var reqRetry = c.maxRetries // Indicates how many times we can retry the request
|
||||||
|
|
||||||
if metadata.contentBody != nil {
|
if metadata.contentBody != nil {
|
||||||
// Check if body is seekable then it is retryable.
|
// Check if body is seekable then it is retryable.
|
||||||
|
|
26
vendor/github.com/minio/minio-go/v7/pkg/lifecycle/lifecycle.go
generated
vendored
26
vendor/github.com/minio/minio-go/v7/pkg/lifecycle/lifecycle.go
generated
vendored
|
@ -434,12 +434,34 @@ func (de DelMarkerExpiration) MarshalXML(enc *xml.Encoder, start xml.StartElemen
|
||||||
return enc.EncodeElement(delMarkerExp(de), start)
|
return enc.EncodeElement(delMarkerExp(de), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllVersionsExpiration represents AllVersionsExpiration actions element in an ILM policy
|
||||||
|
type AllVersionsExpiration struct {
|
||||||
|
XMLName xml.Name `xml:"AllVersionsExpiration" json:"-"`
|
||||||
|
Days int `xml:"Days,omitempty" json:"Days,omitempty"`
|
||||||
|
DeleteMarker ExpireDeleteMarker `xml:"DeleteMarker,omitempty" json:"DeleteMarker,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNull returns true if days field is 0
|
||||||
|
func (e AllVersionsExpiration) IsNull() bool {
|
||||||
|
return e.Days == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalXML satisfies xml.Marshaler to provide custom encoding
|
||||||
|
func (e AllVersionsExpiration) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
|
||||||
|
if e.IsNull() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
type allVersionsExp AllVersionsExpiration
|
||||||
|
return enc.EncodeElement(allVersionsExp(e), start)
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalJSON customizes json encoding by omitting empty values
|
// MarshalJSON customizes json encoding by omitting empty values
|
||||||
func (r Rule) MarshalJSON() ([]byte, error) {
|
func (r Rule) MarshalJSON() ([]byte, error) {
|
||||||
type rule struct {
|
type rule struct {
|
||||||
AbortIncompleteMultipartUpload *AbortIncompleteMultipartUpload `json:"AbortIncompleteMultipartUpload,omitempty"`
|
AbortIncompleteMultipartUpload *AbortIncompleteMultipartUpload `json:"AbortIncompleteMultipartUpload,omitempty"`
|
||||||
Expiration *Expiration `json:"Expiration,omitempty"`
|
Expiration *Expiration `json:"Expiration,omitempty"`
|
||||||
DelMarkerExpiration *DelMarkerExpiration `json:"DelMarkerExpiration,omitempty"`
|
DelMarkerExpiration *DelMarkerExpiration `json:"DelMarkerExpiration,omitempty"`
|
||||||
|
AllVersionsExpiration *AllVersionsExpiration `json:"AllVersionsExpiration,omitempty"`
|
||||||
ID string `json:"ID"`
|
ID string `json:"ID"`
|
||||||
RuleFilter *Filter `json:"Filter,omitempty"`
|
RuleFilter *Filter `json:"Filter,omitempty"`
|
||||||
NoncurrentVersionExpiration *NoncurrentVersionExpiration `json:"NoncurrentVersionExpiration,omitempty"`
|
NoncurrentVersionExpiration *NoncurrentVersionExpiration `json:"NoncurrentVersionExpiration,omitempty"`
|
||||||
|
@ -475,6 +497,9 @@ type rule struct {
|
||||||
if !r.NoncurrentVersionTransition.isNull() {
|
if !r.NoncurrentVersionTransition.isNull() {
|
||||||
newr.NoncurrentVersionTransition = &r.NoncurrentVersionTransition
|
newr.NoncurrentVersionTransition = &r.NoncurrentVersionTransition
|
||||||
}
|
}
|
||||||
|
if !r.AllVersionsExpiration.IsNull() {
|
||||||
|
newr.AllVersionsExpiration = &r.AllVersionsExpiration
|
||||||
|
}
|
||||||
|
|
||||||
return json.Marshal(newr)
|
return json.Marshal(newr)
|
||||||
}
|
}
|
||||||
|
@ -485,6 +510,7 @@ type Rule struct {
|
||||||
AbortIncompleteMultipartUpload AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty" json:"AbortIncompleteMultipartUpload,omitempty"`
|
AbortIncompleteMultipartUpload AbortIncompleteMultipartUpload `xml:"AbortIncompleteMultipartUpload,omitempty" json:"AbortIncompleteMultipartUpload,omitempty"`
|
||||||
Expiration Expiration `xml:"Expiration,omitempty" json:"Expiration,omitempty"`
|
Expiration Expiration `xml:"Expiration,omitempty" json:"Expiration,omitempty"`
|
||||||
DelMarkerExpiration DelMarkerExpiration `xml:"DelMarkerExpiration,omitempty" json:"DelMarkerExpiration,omitempty"`
|
DelMarkerExpiration DelMarkerExpiration `xml:"DelMarkerExpiration,omitempty" json:"DelMarkerExpiration,omitempty"`
|
||||||
|
AllVersionsExpiration AllVersionsExpiration `xml:"AllVersionsExpiration,omitempty" json:"AllVersionsExpiration,omitempty"`
|
||||||
ID string `xml:"ID" json:"ID"`
|
ID string `xml:"ID" json:"ID"`
|
||||||
RuleFilter Filter `xml:"Filter,omitempty" json:"Filter,omitempty"`
|
RuleFilter Filter `xml:"Filter,omitempty" json:"Filter,omitempty"`
|
||||||
NoncurrentVersionExpiration NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty" json:"NoncurrentVersionExpiration,omitempty"`
|
NoncurrentVersionExpiration NoncurrentVersionExpiration `xml:"NoncurrentVersionExpiration,omitempty" json:"NoncurrentVersionExpiration,omitempty"`
|
||||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -486,7 +486,7 @@ github.com/miekg/dns
|
||||||
# github.com/minio/md5-simd v1.1.2
|
# github.com/minio/md5-simd v1.1.2
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
github.com/minio/md5-simd
|
github.com/minio/md5-simd
|
||||||
# github.com/minio/minio-go/v7 v7.0.79
|
# github.com/minio/minio-go/v7 v7.0.80
|
||||||
## explicit; go 1.22
|
## explicit; go 1.22
|
||||||
github.com/minio/minio-go/v7
|
github.com/minio/minio-go/v7
|
||||||
github.com/minio/minio-go/v7/pkg/cors
|
github.com/minio/minio-go/v7/pkg/cors
|
||||||
|
|
|
@ -117,13 +117,13 @@ const extended = gtsApi.injectEndpoints({
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeDomainPermissionDraft: build.mutation<DomainPerm, { id: string, ignore_target?: boolean }>({
|
removeDomainPermissionDraft: build.mutation<DomainPerm, { id: string, exclude_target?: boolean }>({
|
||||||
query: ({ id, ignore_target }) => ({
|
query: ({ id, exclude_target }) => ({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: `/api/v1/admin/domain_permission_drafts/${id}/remove`,
|
url: `/api/v1/admin/domain_permission_drafts/${id}/remove`,
|
||||||
asForm: true,
|
asForm: true,
|
||||||
body: {
|
body: {
|
||||||
ignore_target: ignore_target,
|
exclude_target: exclude_target,
|
||||||
},
|
},
|
||||||
discardEmpty: true
|
discardEmpty: true
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { gtsApi } from "../../gts-api";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
DomainPerm,
|
||||||
|
DomainPermExcludeCreateParams,
|
||||||
|
DomainPermExcludeSearchParams,
|
||||||
|
DomainPermExcludeSearchResp,
|
||||||
|
} from "../../../types/domain-permission";
|
||||||
|
import parse from "parse-link-header";
|
||||||
|
|
||||||
|
const extended = gtsApi.injectEndpoints({
|
||||||
|
endpoints: (build) => ({
|
||||||
|
searchDomainPermissionExcludes: build.query<DomainPermExcludeSearchResp, DomainPermExcludeSearchParams>({
|
||||||
|
query: (form) => {
|
||||||
|
const params = new(URLSearchParams);
|
||||||
|
Object.entries(form).forEach(([k, v]) => {
|
||||||
|
if (v !== undefined) {
|
||||||
|
params.append(k, v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let query = "";
|
||||||
|
if (params.size !== 0) {
|
||||||
|
query = `?${params.toString()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: `/api/v1/admin/domain_permission_excludes${query}`
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// Headers required for paging.
|
||||||
|
transformResponse: (apiResp: DomainPerm[], meta) => {
|
||||||
|
const excludes = apiResp;
|
||||||
|
const linksStr = meta?.response?.headers.get("Link");
|
||||||
|
const links = parse(linksStr);
|
||||||
|
return { excludes, links };
|
||||||
|
},
|
||||||
|
// Only provide TRANSFORMED tag id since this model is not the same
|
||||||
|
// as getDomainPermissionExclude model (due to transformResponse).
|
||||||
|
providesTags: [{ type: "DomainPermissionExclude", id: "TRANSFORMED" }]
|
||||||
|
}),
|
||||||
|
|
||||||
|
getDomainPermissionExclude: build.query<DomainPerm, string>({
|
||||||
|
query: (id) => ({
|
||||||
|
url: `/api/v1/admin/domain_permission_excludes/${id}`
|
||||||
|
}),
|
||||||
|
providesTags: (_result, _error, id) => [
|
||||||
|
{ type: 'DomainPermissionExclude', id }
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
createDomainPermissionExclude: build.mutation<DomainPerm, DomainPermExcludeCreateParams>({
|
||||||
|
query: (formData) => ({
|
||||||
|
method: "POST",
|
||||||
|
url: `/api/v1/admin/domain_permission_excludes`,
|
||||||
|
asForm: true,
|
||||||
|
body: formData,
|
||||||
|
discardEmpty: true
|
||||||
|
}),
|
||||||
|
invalidatesTags: [{ type: "DomainPermissionExclude", id: "TRANSFORMED" }],
|
||||||
|
}),
|
||||||
|
|
||||||
|
deleteDomainPermissionExclude: build.mutation<DomainPerm, string>({
|
||||||
|
query: (id) => ({
|
||||||
|
method: "DELETE",
|
||||||
|
url: `/api/v1/admin/domain_permission_excludes/${id}`,
|
||||||
|
}),
|
||||||
|
invalidatesTags: (res, _error, id) =>
|
||||||
|
res
|
||||||
|
? [
|
||||||
|
{ type: "DomainPermissionExclude", id },
|
||||||
|
{ type: "DomainPermissionExclude", id: "TRANSFORMED" },
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View domain permission excludes.
|
||||||
|
*/
|
||||||
|
const useLazySearchDomainPermissionExcludesQuery = extended.useLazySearchDomainPermissionExcludesQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get domain permission exclude with the given ID.
|
||||||
|
*/
|
||||||
|
const useGetDomainPermissionExcludeQuery = extended.useGetDomainPermissionExcludeQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a domain permission exclude with the given parameters.
|
||||||
|
*/
|
||||||
|
const useCreateDomainPermissionExcludeMutation = extended.useCreateDomainPermissionExcludeMutation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a domain permission exclude.
|
||||||
|
*/
|
||||||
|
const useDeleteDomainPermissionExcludeMutation = extended.useDeleteDomainPermissionExcludeMutation;
|
||||||
|
|
||||||
|
export {
|
||||||
|
useLazySearchDomainPermissionExcludesQuery,
|
||||||
|
useGetDomainPermissionExcludeQuery,
|
||||||
|
useCreateDomainPermissionExcludeMutation,
|
||||||
|
useDeleteDomainPermissionExcludeMutation,
|
||||||
|
};
|
|
@ -170,6 +170,7 @@ export const gtsApi = createApi({
|
||||||
"DefaultInteractionPolicies",
|
"DefaultInteractionPolicies",
|
||||||
"InteractionRequest",
|
"InteractionRequest",
|
||||||
"DomainPermissionDraft",
|
"DomainPermissionDraft",
|
||||||
|
"DomainPermissionExclude"
|
||||||
],
|
],
|
||||||
endpoints: (build) => ({
|
endpoints: (build) => ({
|
||||||
instanceV1: build.query<InstanceV1, void>({
|
instanceV1: build.query<InstanceV1, void>({
|
||||||
|
|
|
@ -135,36 +135,6 @@ export interface DomainPermDraftSearchParams {
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for POST to /api/v1/admin/domain_permission_drafts/{id}/accept.
|
|
||||||
*/
|
|
||||||
export interface DomainPermDraftAcceptParams {
|
|
||||||
/**
|
|
||||||
* ID of the domain permission draft.
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
overwrite?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for POST to /api/v1/admin/domain_permission_drafts/{id}/accept.
|
|
||||||
*/
|
|
||||||
export interface DomainPermDraftRejectParams {
|
|
||||||
/**
|
|
||||||
* ID of the domain permission draft.
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/**
|
|
||||||
* When removing the domain permission draft, also create a domain ignore entry for
|
|
||||||
* the target domain, so that drafts will not be created for this domain in the future.
|
|
||||||
*/
|
|
||||||
ignore_target?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DomainPermDraftSearchResp {
|
export interface DomainPermDraftSearchResp {
|
||||||
drafts: DomainPerm[];
|
drafts: DomainPerm[];
|
||||||
links: Links | null;
|
links: Links | null;
|
||||||
|
@ -196,3 +166,50 @@ export interface DomainPermDraftCreateParams {
|
||||||
*/
|
*/
|
||||||
private_comment?: string;
|
private_comment?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for GET to /api/v1/admin/domain_permission_excludes.
|
||||||
|
*/
|
||||||
|
export interface DomainPermExcludeSearchParams {
|
||||||
|
/**
|
||||||
|
* Return only excludes that target the given domain.
|
||||||
|
*/
|
||||||
|
domain?: string;
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
max_id?: string;
|
||||||
|
/**
|
||||||
|
* Return only items *NEWER* than the given since ID.
|
||||||
|
* The item with the specified ID will not be included in the response.
|
||||||
|
*/
|
||||||
|
since_id?: string;
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
min_id?: string;
|
||||||
|
/**
|
||||||
|
* Number of items to return.
|
||||||
|
*/
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DomainPermExcludeSearchResp {
|
||||||
|
excludes: DomainPerm[];
|
||||||
|
links: Links | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DomainPermExcludeCreateParams {
|
||||||
|
/**
|
||||||
|
* Domain to create the permission exclude for.
|
||||||
|
*/
|
||||||
|
domain: string;
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
private_comment?: string;
|
||||||
|
}
|
||||||
|
|
|
@ -234,7 +234,7 @@ nav.menu-tree {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
border-bottom: 0.1rem dotted $gray1;
|
border-bottom: 0.15rem dotted $gray1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,8 +1359,10 @@ button.tab-button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain-permission-drafts-view {
|
.domain-permission-drafts-view,
|
||||||
.domain-permission-draft {
|
.domain-permission-excludes-view {
|
||||||
|
.domain-permission-draft,
|
||||||
|
.domain-permission-exclude {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
|
|
|
@ -131,7 +131,7 @@ function HandleDraft({ id, permType, backLocation }: { id: string, permType: Per
|
||||||
const form = {
|
const form = {
|
||||||
acceptOrRemove: useTextInput("accept_or_remove", { defaultValue: "accept" }),
|
acceptOrRemove: useTextInput("accept_or_remove", { defaultValue: "accept" }),
|
||||||
overwrite: useBoolInput("overwrite"),
|
overwrite: useBoolInput("overwrite"),
|
||||||
ignore_target: useBoolInput("ignore_target"),
|
exclude_target: useBoolInput("exclude_target"),
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClick = (e) => {
|
const onClick = (e) => {
|
||||||
|
@ -144,8 +144,8 @@ function HandleDraft({ id, permType, backLocation }: { id: string, permType: Per
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const ignore_target = form.ignore_target.value;
|
const exclude_target = form.exclude_target.value;
|
||||||
remove({id, ignore_target}).then(res => {
|
remove({id, exclude_target}).then(res => {
|
||||||
if ("data" in res) {
|
if ("data" in res) {
|
||||||
setLocation(backLocation);
|
setLocation(backLocation);
|
||||||
}
|
}
|
||||||
|
@ -178,8 +178,8 @@ function HandleDraft({ id, permType, backLocation }: { id: string, permType: Per
|
||||||
{ form.acceptOrRemove.value === "remove" &&
|
{ form.acceptOrRemove.value === "remove" &&
|
||||||
<>
|
<>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
field={form.ignore_target}
|
field={form.exclude_target}
|
||||||
label={`Add a domain permission ignore for this domain`}
|
label={`Add a domain permission exclude for this domain`}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { useParams } from "wouter";
|
||||||
|
import Loading from "../../../../components/loading";
|
||||||
|
import { useBaseUrl } from "../../../../lib/navigation/util";
|
||||||
|
import BackButton from "../../../../components/back-button";
|
||||||
|
import { Error as ErrorC } from "../../../../components/error";
|
||||||
|
import UsernameLozenge from "../../../../components/username-lozenge";
|
||||||
|
import { useGetDomainPermissionExcludeQuery } from "../../../../lib/query/admin/domain-permissions/excludes";
|
||||||
|
|
||||||
|
export default function DomainPermissionExcludeDetail() {
|
||||||
|
const baseUrl = useBaseUrl();
|
||||||
|
const backLocation: string = history.state?.backLocation ?? `~${baseUrl}`;
|
||||||
|
const params = useParams();
|
||||||
|
|
||||||
|
let id = params.permExcludeId as string | undefined;
|
||||||
|
if (!id) {
|
||||||
|
throw "no perm ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: permExclude,
|
||||||
|
isLoading,
|
||||||
|
isFetching,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
} = useGetDomainPermissionExcludeQuery(id);
|
||||||
|
|
||||||
|
if (isLoading || isFetching) {
|
||||||
|
return <Loading />;
|
||||||
|
} else if (isError) {
|
||||||
|
return <ErrorC error={error} />;
|
||||||
|
} else if (permExclude === undefined) {
|
||||||
|
return <ErrorC error={new Error("permission exclude was undefined")} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = permExclude.created_at ? new Date(permExclude.created_at).toDateString(): "unknown";
|
||||||
|
const domain = permExclude.domain;
|
||||||
|
const permType = permExclude.permission_type;
|
||||||
|
if (!permType) {
|
||||||
|
return <ErrorC error={new Error("permission_type was undefined")} />;
|
||||||
|
}
|
||||||
|
const publicComment = permExclude.public_comment ?? "[none]";
|
||||||
|
const privateComment = permExclude.private_comment ?? "[none]";
|
||||||
|
const subscriptionID = permExclude.subscription_id ?? "[none]";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="domain-permission-exclude-details">
|
||||||
|
<h1><BackButton to={backLocation} /> Domain Permission Exclude Detail</h1>
|
||||||
|
<dl className="info-list">
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Created</dt>
|
||||||
|
<dd><time dateTime={permExclude.created_at}>{created}</time></dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Created By</dt>
|
||||||
|
<dd>
|
||||||
|
<UsernameLozenge
|
||||||
|
account={permExclude.created_by}
|
||||||
|
linkTo={`~/settings/moderation/accounts/${permExclude.created_by}`}
|
||||||
|
backLocation={`~${location}`}
|
||||||
|
/>
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Domain</dt>
|
||||||
|
<dd>{domain}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Permission type</dt>
|
||||||
|
<dd className={`permission-type ${permType}`}>
|
||||||
|
<i
|
||||||
|
aria-hidden={true}
|
||||||
|
className={`fa fa-${permType === "allow" ? "check" : "close"}`}
|
||||||
|
></i>
|
||||||
|
{permType}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Private comment</dt>
|
||||||
|
<dd>{privateComment}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Public comment</dt>
|
||||||
|
<dd>{publicComment}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Subscription ID</dt>
|
||||||
|
<dd>{subscriptionID}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
<HandleExclude
|
||||||
|
id={id}
|
||||||
|
backLocation={backLocation}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HandleExclude({ id, backLocation }: { id: string, backLocation: string }) {
|
||||||
|
return <></>;
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { ReactNode, useEffect, useMemo } from "react";
|
||||||
|
|
||||||
|
import { useTextInput } from "../../../../lib/form";
|
||||||
|
import { PageableList } from "../../../../components/pageable-list";
|
||||||
|
import MutationButton from "../../../../components/form/mutation-button";
|
||||||
|
import { useLocation, useSearch } from "wouter";
|
||||||
|
import { useDeleteDomainPermissionExcludeMutation, useLazySearchDomainPermissionExcludesQuery } from "../../../../lib/query/admin/domain-permissions/excludes";
|
||||||
|
import { DomainPerm } from "../../../../lib/types/domain-permission";
|
||||||
|
import { Error as ErrorC } from "../../../../components/error";
|
||||||
|
import { Select, TextInput } from "../../../../components/form/inputs";
|
||||||
|
import { formDomainValidator } from "../../../../lib/util/formvalidators";
|
||||||
|
|
||||||
|
export default function DomainPermissionExcludesSearch() {
|
||||||
|
return (
|
||||||
|
<div className="domain-permission-excludes-view">
|
||||||
|
<div className="form-section-docs">
|
||||||
|
<h1>Domain Permission Excludes</h1>
|
||||||
|
<p>
|
||||||
|
You can use the form below to search through domain permission excludes.
|
||||||
|
<br/>
|
||||||
|
Domain permission excludes are domain block or domain allow entries that are not yet in force.
|
||||||
|
<br/>
|
||||||
|
You can choose to accept or remove a exclude.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<DomainPermissionExcludesSearchForm />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function DomainPermissionExcludesSearchForm() {
|
||||||
|
const [ location, setLocation ] = useLocation();
|
||||||
|
const search = useSearch();
|
||||||
|
const urlQueryParams = useMemo(() => new URLSearchParams(search), [search]);
|
||||||
|
const hasParams = urlQueryParams.size != 0;
|
||||||
|
const [ searchExcludes, searchRes ] = useLazySearchDomainPermissionExcludesQuery();
|
||||||
|
|
||||||
|
const form = {
|
||||||
|
domain: useTextInput("domain", {
|
||||||
|
defaultValue: urlQueryParams.get("domain") ?? "",
|
||||||
|
validator: formDomainValidator,
|
||||||
|
}),
|
||||||
|
limit: useTextInput("limit", { defaultValue: urlQueryParams.get("limit") ?? "20" })
|
||||||
|
};
|
||||||
|
|
||||||
|
// On mount, if urlQueryParams were provided,
|
||||||
|
// trigger the search. For example, if page
|
||||||
|
// was accessed at /search?origin=local&limit=20,
|
||||||
|
// then run a search with origin=local and
|
||||||
|
// limit=20 and immediately render the results.
|
||||||
|
//
|
||||||
|
// If no urlQueryParams set, trigger default
|
||||||
|
// search (first page, no filtering).
|
||||||
|
useEffect(() => {
|
||||||
|
if (hasParams) {
|
||||||
|
searchExcludes(Object.fromEntries(urlQueryParams));
|
||||||
|
} else {
|
||||||
|
setLocation(location + "?limit=20");
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
urlQueryParams,
|
||||||
|
hasParams,
|
||||||
|
searchExcludes,
|
||||||
|
location,
|
||||||
|
setLocation,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Rather than triggering the search directly,
|
||||||
|
// the "submit" button changes the location
|
||||||
|
// based on form field params, and lets the
|
||||||
|
// useEffect hook above actually do the search.
|
||||||
|
function submitQuery(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// Parse query parameters.
|
||||||
|
const entries = Object.entries(form).map(([k, v]) => {
|
||||||
|
// Take only defined form fields.
|
||||||
|
if (v.value === undefined || v.value.length === 0 || v.value === "any") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return [[k, v.value]];
|
||||||
|
}).flatMap(kv => {
|
||||||
|
// Remove any nulls.
|
||||||
|
return kv || [];
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchParams = new URLSearchParams(entries);
|
||||||
|
setLocation(location + "?" + searchParams.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Location to return to when user clicks "back" on the detail view.
|
||||||
|
const backLocation = location + (hasParams ? `?${urlQueryParams}` : "");
|
||||||
|
|
||||||
|
// Function to map an item to a list entry.
|
||||||
|
function itemToEntry(exclude: DomainPerm): ReactNode {
|
||||||
|
return (
|
||||||
|
<ExcludeListEntry
|
||||||
|
key={exclude.id}
|
||||||
|
permExclude={exclude}
|
||||||
|
linkTo={`/excludes/${exclude.id}`}
|
||||||
|
backLocation={backLocation}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<form
|
||||||
|
onSubmit={submitQuery}
|
||||||
|
// Prevent password managers
|
||||||
|
// trying to fill in fields.
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<TextInput
|
||||||
|
field={form.domain}
|
||||||
|
label={`Domain (without "https://" prefix)`}
|
||||||
|
placeholder="example.org"
|
||||||
|
autoCapitalize="none"
|
||||||
|
spellCheck="false"
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
field={form.limit}
|
||||||
|
label="Items per page"
|
||||||
|
options={
|
||||||
|
<>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
></Select>
|
||||||
|
<MutationButton
|
||||||
|
disabled={false}
|
||||||
|
label={"Search"}
|
||||||
|
result={searchRes}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
<PageableList
|
||||||
|
isLoading={searchRes.isLoading}
|
||||||
|
isFetching={searchRes.isFetching}
|
||||||
|
isSuccess={searchRes.isSuccess}
|
||||||
|
items={searchRes.data?.excludes}
|
||||||
|
itemToEntry={itemToEntry}
|
||||||
|
isError={searchRes.isError}
|
||||||
|
error={searchRes.error}
|
||||||
|
emptyMessage={<b>No excludes found that match your query.</b>}
|
||||||
|
prevNextLinks={searchRes.data?.links}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExcludeEntryProps {
|
||||||
|
permExclude: DomainPerm;
|
||||||
|
linkTo: string;
|
||||||
|
backLocation: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ExcludeListEntry({ permExclude, linkTo, backLocation }: ExcludeEntryProps) {
|
||||||
|
const [ _location, setLocation ] = useLocation();
|
||||||
|
const [ deleteExclude, deleteResult ] = useDeleteDomainPermissionExcludeMutation();
|
||||||
|
|
||||||
|
const domain = permExclude.domain;
|
||||||
|
const privateComment = permExclude.private_comment ?? "[none]";
|
||||||
|
const id = permExclude.id;
|
||||||
|
if (!id) {
|
||||||
|
return <ErrorC error={new Error("id was undefined")} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className={`pseudolink domain-permission-exclude entry`}
|
||||||
|
aria-label={`Exclude ${domain}`}
|
||||||
|
title={`Exclude ${domain}`}
|
||||||
|
onClick={() => {
|
||||||
|
// When clicking on a exclude, direct
|
||||||
|
// to the detail view for that exclude.
|
||||||
|
setLocation(linkTo, {
|
||||||
|
// Store the back location in history so
|
||||||
|
// the detail view can use it to return to
|
||||||
|
// this page (including query parameters).
|
||||||
|
state: { backLocation: backLocation }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<h3>{`Exclude ${domain}`}</h3>
|
||||||
|
<dl className="info-list">
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Domain:</dt>
|
||||||
|
<dd className="text-cutoff">{domain}</dd>
|
||||||
|
</div>
|
||||||
|
<div className="info-list-entry">
|
||||||
|
<dt>Private comment:</dt>
|
||||||
|
<dd className="text-cutoff">{privateComment}</dd>
|
||||||
|
</div>
|
||||||
|
</dl>
|
||||||
|
<div className="action-buttons">
|
||||||
|
<MutationButton
|
||||||
|
label={`Delete exclude`}
|
||||||
|
title={`Delete exclude`}
|
||||||
|
type="button"
|
||||||
|
className="button danger"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
deleteExclude(id);
|
||||||
|
}}
|
||||||
|
disabled={false}
|
||||||
|
showError={true}
|
||||||
|
result={deleteResult}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import useFormSubmit from "../../../../lib/form/submit";
|
||||||
|
import { useCreateDomainPermissionExcludeMutation } from "../../../../lib/query/admin/domain-permissions/excludes";
|
||||||
|
import { useTextInput } from "../../../../lib/form";
|
||||||
|
import { formDomainValidator } from "../../../../lib/util/formvalidators";
|
||||||
|
import MutationButton from "../../../../components/form/mutation-button";
|
||||||
|
import { TextArea, TextInput } from "../../../../components/form/inputs";
|
||||||
|
import { useLocation } from "wouter";
|
||||||
|
|
||||||
|
export default function DomainPermissionExcludeNew() {
|
||||||
|
const [ _location, setLocation ] = useLocation();
|
||||||
|
|
||||||
|
const form = {
|
||||||
|
domain: useTextInput("domain", {
|
||||||
|
validator: formDomainValidator,
|
||||||
|
}),
|
||||||
|
private_comment: useTextInput("private_comment"),
|
||||||
|
};
|
||||||
|
|
||||||
|
const [formSubmit, result] = useFormSubmit(
|
||||||
|
form,
|
||||||
|
useCreateDomainPermissionExcludeMutation(),
|
||||||
|
{
|
||||||
|
changedOnly: false,
|
||||||
|
onFinish: (res) => {
|
||||||
|
if (res.data) {
|
||||||
|
// Creation successful,
|
||||||
|
// redirect to excludes overview.
|
||||||
|
setLocation(`/excludes/search`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form
|
||||||
|
onSubmit={formSubmit}
|
||||||
|
// Prevent password managers
|
||||||
|
// trying to fill in fields.
|
||||||
|
autoComplete="off"
|
||||||
|
>
|
||||||
|
<div className="form-section-docs">
|
||||||
|
<h2>New Domain Permission Exclude</h2>
|
||||||
|
<p>
|
||||||
|
You can use the form below to create a new domain permission exclude.
|
||||||
|
<br/>
|
||||||
|
Domain permission excludes are domain block or domain allow entries that are not yet in force.
|
||||||
|
<br/>
|
||||||
|
You can choose to accept or remove a exclude.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
field={form.domain}
|
||||||
|
label={`Domain (without "https://" prefix)`}
|
||||||
|
placeholder="example.org"
|
||||||
|
autoCapitalize="none"
|
||||||
|
spellCheck="false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextArea
|
||||||
|
field={form.private_comment}
|
||||||
|
label={"Private comment"}
|
||||||
|
placeholder="This domain is like unto a clown car full of clowns, I suggest we block it forthwith."
|
||||||
|
autoCapitalize="sentences"
|
||||||
|
rows={3}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MutationButton
|
||||||
|
label="Save"
|
||||||
|
result={result}
|
||||||
|
disabled={!form.domain.value || !form.domain.valid}
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
|
@ -133,6 +133,23 @@ function ModerationDomainPermsMenu() {
|
||||||
icon="fa-plus"
|
icon="fa-plus"
|
||||||
/>
|
/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
name="Excludes"
|
||||||
|
itemUrl="excludes"
|
||||||
|
defaultChild="search"
|
||||||
|
icon="fa-minus-square"
|
||||||
|
>
|
||||||
|
<MenuItem
|
||||||
|
name="Search"
|
||||||
|
itemUrl="search"
|
||||||
|
icon="fa-list"
|
||||||
|
/>
|
||||||
|
<MenuItem
|
||||||
|
name="New exclude"
|
||||||
|
itemUrl="new"
|
||||||
|
icon="fa-plus"
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ import AccountDetail from "./accounts/detail";
|
||||||
import DomainPermissionDraftsSearch from "./domain-permissions/drafts";
|
import DomainPermissionDraftsSearch from "./domain-permissions/drafts";
|
||||||
import DomainPermissionDraftNew from "./domain-permissions/drafts/new";
|
import DomainPermissionDraftNew from "./domain-permissions/drafts/new";
|
||||||
import DomainPermissionDraftDetail from "./domain-permissions/drafts/detail";
|
import DomainPermissionDraftDetail from "./domain-permissions/drafts/detail";
|
||||||
|
import DomainPermissionExcludeDetail from "./domain-permissions/excludes/detail";
|
||||||
|
import DomainPermissionExcludesSearch from "./domain-permissions/excludes";
|
||||||
|
import DomainPermissionExcludeNew from "./domain-permissions/excludes/new";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
EXPORTED COMPONENTS
|
EXPORTED COMPONENTS
|
||||||
|
@ -145,6 +148,9 @@ function ModerationDomainPermsRouter() {
|
||||||
<Route path="/drafts/search" component={DomainPermissionDraftsSearch} />
|
<Route path="/drafts/search" component={DomainPermissionDraftsSearch} />
|
||||||
<Route path="/drafts/new" component={DomainPermissionDraftNew} />
|
<Route path="/drafts/new" component={DomainPermissionDraftNew} />
|
||||||
<Route path="/drafts/:permDraftId" component={DomainPermissionDraftDetail} />
|
<Route path="/drafts/:permDraftId" component={DomainPermissionDraftDetail} />
|
||||||
|
<Route path="/excludes/search" component={DomainPermissionExcludesSearch} />
|
||||||
|
<Route path="/excludes/new" component={DomainPermissionExcludeNew} />
|
||||||
|
<Route path="/excludes/:excludeId" component={DomainPermissionExcludeDetail} />
|
||||||
<Route path="/:permType" component={DomainPermissionsOverview} />
|
<Route path="/:permType" component={DomainPermissionsOverview} />
|
||||||
<Route path="/:permType/:domain" component={DomainPermDetail} />
|
<Route path="/:permType/:domain" component={DomainPermDetail} />
|
||||||
<Route><Redirect to="/blocks"/></Route>
|
<Route><Redirect to="/blocks"/></Route>
|
||||||
|
|
Loading…
Reference in a new issue