mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-22 03:36:39 +00:00
bwap bwap
This commit is contained in:
parent
51cb6cae16
commit
cfe2b61bdd
99
internal/api/client/admin/domainpermissiondraft.go
Normal file
99
internal/api/client/admin/domainpermissiondraft.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
)
|
||||
|
||||
// DomainPermissionDraftGETHandler swagger:operation GET /api/v1/admin/domain_permission_drafts/{id} domainPermissionDraftGet
|
||||
//
|
||||
// Get domain permission draft with the given ID.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: id
|
||||
// required: true
|
||||
// in: path
|
||||
// description: ID of the domain permission draft.
|
||||
// type: string
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Domain permission draft.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainPermission"
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '403':
|
||||
// description: forbidden
|
||||
// '404':
|
||||
// description: not found
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) DomainPermissionDraftGETHandler(c *gin.Context) {
|
||||
authed, err := oauth.Authed(c, true, true, true, true)
|
||||
if err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if !*authed.User.Admin {
|
||||
err := fmt.Errorf("user %s not an admin", authed.User.ID)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
permDraft, errWithCode := m.processor.Admin().DomainPermissionDraftGet(c.Request.Context(), id)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, permDraft)
|
||||
}
|
173
internal/api/client/admin/domainpermissiondraftcreate.go
Normal file
173
internal/api/client/admin/domainpermissiondraftcreate.go
Normal file
|
@ -0,0 +1,173 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
)
|
||||
|
||||
// DomainPermissionDraftsPOSTHandler swagger:operation POST /api/v1/admin/domain_permission_drafts domainPermissionDraftCreate
|
||||
//
|
||||
// Create a domain permission draft with the given parameters.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// consumes:
|
||||
// - multipart/form-data
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: domain
|
||||
// in: formData
|
||||
// description: Domain to create the permission draft for.
|
||||
// type: string
|
||||
// -
|
||||
// name: permission_type
|
||||
// type: string
|
||||
// description: Create a draft "allow" or a draft "block".
|
||||
// in: query
|
||||
// -
|
||||
// name: obfuscate
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Obfuscate the name of the domain when serving it publicly.
|
||||
// Eg., `example.org` becomes something like `ex***e.org`.
|
||||
// type: boolean
|
||||
// -
|
||||
// name: public_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Public comment about this domain permission.
|
||||
// This will be displayed alongside the domain permission if you choose to share permissions.
|
||||
// type: string
|
||||
// -
|
||||
// name: private_comment
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Private comment about this domain permission. Will only be shown to other admins, so this
|
||||
// is a useful way of internally keeping track of why a certain domain ended up permissioned.
|
||||
// type: string
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: The newly created domain permission draft.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainPermission"
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '403':
|
||||
// description: forbidden
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) DomainPermissionDraftsPOSTHandler(c *gin.Context) {
|
||||
authed, err := oauth.Authed(c, true, true, true, true)
|
||||
if err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if !*authed.User.Admin {
|
||||
err := fmt.Errorf("user %s not an admin", authed.User.ID)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if authed.Account.IsMoving() {
|
||||
apiutil.ForbiddenAfterMove(c)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
// Parse + validate form.
|
||||
form := new(apimodel.DomainPermissionRequest)
|
||||
if err := c.ShouldBind(form); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if form.Domain == "" {
|
||||
const errText = "domain must be set"
|
||||
errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
permType gtsmodel.DomainPermissionType
|
||||
errText string
|
||||
)
|
||||
|
||||
switch pt := form.PermissionType; pt {
|
||||
case "block":
|
||||
permType = gtsmodel.DomainPermissionBlock
|
||||
case "allow":
|
||||
permType = gtsmodel.DomainPermissionAllow
|
||||
case "":
|
||||
errText = "permission_type not set, must be one of block or allow"
|
||||
default:
|
||||
errText = fmt.Sprintf("permission_type %s not recognized, must be one of block or allow", pt)
|
||||
}
|
||||
|
||||
if errText != "" {
|
||||
errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
permDraft, errWithCode := m.processor.Admin().DomainPermissionDraftCreate(
|
||||
c.Request.Context(),
|
||||
authed.Account,
|
||||
form.Domain,
|
||||
permType,
|
||||
form.Obfuscate,
|
||||
form.PublicComment,
|
||||
form.PrivateComment,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, permDraft)
|
||||
}
|
184
internal/api/client/admin/domainpermissiondrafts.go
Normal file
184
internal/api/client/admin/domainpermissiondrafts.go
Normal file
|
@ -0,0 +1,184 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// DomainPermissionDraftsGETHandler swagger:operation GET /api/v1/admin/domain_permission_drafts domainPermissionDraftsGet
|
||||
//
|
||||
// View domain permission drafts.
|
||||
//
|
||||
// The drafts will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer).
|
||||
//
|
||||
// The next and previous queries can be parsed from the returned Link header.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ```
|
||||
// <https://example.org/api/v1/admin/domain_permission_drafts?limit=20&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/admin/domain_permission_drafts?limit=20&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev"
|
||||
// ````
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: subscription_id
|
||||
// type: string
|
||||
// description: Show only drafts created by the given subscription ID.
|
||||
// in: query
|
||||
// -
|
||||
// name: domain
|
||||
// type: string
|
||||
// description: Return only drafts that target the given domain.
|
||||
// in: query
|
||||
// -
|
||||
// name: permission_type
|
||||
// type: string
|
||||
// description: Filter on "block" or "allow" type drafts.
|
||||
// in: query
|
||||
// -
|
||||
// name: max_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only items *OLDER* than the given max ID (for paging downwards).
|
||||
// The item with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// -
|
||||
// name: since_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only items *NEWER* than the given since ID.
|
||||
// The item with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// -
|
||||
// name: min_id
|
||||
// type: string
|
||||
// description: >-
|
||||
// Return only items immediately *NEWER* than the given min ID (for paging upwards).
|
||||
// The item with the specified ID will not be included in the response.
|
||||
// in: query
|
||||
// -
|
||||
// name: limit
|
||||
// type: integer
|
||||
// description: Number of items to return.
|
||||
// default: 20
|
||||
// minimum: 1
|
||||
// maximum: 100
|
||||
// in: query
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: Domain permission drafts.
|
||||
// schema:
|
||||
// type: array
|
||||
// items:
|
||||
// "$ref": "#/definitions/domainPermission"
|
||||
// headers:
|
||||
// Link:
|
||||
// type: string
|
||||
// description: Links to the next and previous queries.
|
||||
// '400':
|
||||
// description: bad request
|
||||
// '401':
|
||||
// description: unauthorized
|
||||
// '403':
|
||||
// description: forbidden
|
||||
// '404':
|
||||
// description: not found
|
||||
// '406':
|
||||
// description: not acceptable
|
||||
// '500':
|
||||
// description: internal server error
|
||||
func (m *Module) DomainPermissionDraftsGETHandler(c *gin.Context) {
|
||||
authed, err := oauth.Authed(c, true, true, true, true)
|
||||
if err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if !*authed.User.Admin {
|
||||
err := fmt.Errorf("user %s not an admin", authed.User.ID)
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
permType := c.Query(apiutil.DomainPermissionPermTypeKey)
|
||||
switch permType {
|
||||
case "", "block", "allow":
|
||||
// No problem.
|
||||
|
||||
default:
|
||||
// Invalid.
|
||||
text := fmt.Sprintf(
|
||||
"permission_type %s not recognized, valid values are empty string, block, or allow",
|
||||
permType,
|
||||
)
|
||||
errWithCode := gtserror.NewErrorBadRequest(errors.New(text), text)
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
page, errWithCode := paging.ParseIDPage(c, 1, 200, 20)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
resp, errWithCode := m.processor.Admin().DomainPermissionDraftsGet(
|
||||
c.Request.Context(),
|
||||
c.Query(apiutil.DomainPermissionSubscriptionIDKey),
|
||||
c.Query(apiutil.DomainPermissionDomainKey),
|
||||
gtsmodel.NewDomainPermissionType(permType),
|
||||
page,
|
||||
)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if resp.LinkHeader != "" {
|
||||
c.Header("Link", resp.LinkHeader)
|
||||
}
|
||||
|
||||
apiutil.JSON(c, http.StatusOK, resp.Items)
|
||||
}
|
|
@ -63,28 +63,74 @@ type DomainPermission struct {
|
|||
CreatedAt string `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
// DomainPermissionSubscription represents an auto-refreshing subscription to a list of domain permissions (allows, blocks).
|
||||
//
|
||||
// swagger:model domainPermission
|
||||
type DomainPermissionSubscription struct {
|
||||
// The ID of the domain permission subscription.
|
||||
// example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||
// readonly: true
|
||||
ID string `json:"id"`
|
||||
// The type of domain permission subscription (allow, block).
|
||||
// example: block
|
||||
PermissionType string `json:"permission_type"`
|
||||
// If true, domain permissions arising from this subscription will be created as drafts that must be approved by a moderator to take effect. If false, domain permissions from this subscription will come into force immediately.
|
||||
// example: true
|
||||
AsDraft bool `json:"as_draft"`
|
||||
// ID of the account that created this subscription.
|
||||
// example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||
// readonly: true
|
||||
CreatedByAccountID string `json:"created_by_account_id"`
|
||||
// MIME content type to expect at URI.
|
||||
// example: text/csv
|
||||
ContentType string `json:"content_type"`
|
||||
// URI to call in order to fetch the permissions list.
|
||||
// example: https://www.example.org/blocklists/list1.csv
|
||||
URI string `json:"uri"`
|
||||
// (Optional) username to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchUsername string `json:"fetch_username"`
|
||||
// (Optional) password to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchPassword string `json:"fetch_password"`
|
||||
// Time at which the most recent fetch was attempted (ISO 8601 Datetime).
|
||||
// example: 2021-07-30T09:20:25+00:00
|
||||
// readonly: true
|
||||
FetchedAt string `json:"fetched_at"`
|
||||
// If most recent fetch attempt failed, this field will contain an error message related to the fetch attempt.
|
||||
// example: Oopsie doopsie, we made a fucky wucky.
|
||||
// readonly: true
|
||||
Error string `json:"error"`
|
||||
// Count of domain permission entries discovered at URI.
|
||||
// example: 53
|
||||
// readonly: true
|
||||
Count uint64 `json:"count"`
|
||||
}
|
||||
|
||||
// DomainPermissionRequest is the form submitted as a POST to create a new domain permission entry (allow/block).
|
||||
//
|
||||
// swagger:ignore
|
||||
type DomainPermissionRequest struct {
|
||||
// A list of domains for which this permission request should apply.
|
||||
// Only used if import=true is specified.
|
||||
Domains *multipart.FileHeader `form:"domains" json:"domains" xml:"domains"`
|
||||
Domains *multipart.FileHeader `form:"domains" json:"domains"`
|
||||
// A single domain for which this permission request should apply.
|
||||
// Only used if import=true is NOT specified or if import=false.
|
||||
// example: example.org
|
||||
Domain string `form:"domain" json:"domain" xml:"domain"`
|
||||
Domain string `form:"domain" json:"domain"`
|
||||
// Obfuscate the domain name when displaying this permission entry publicly.
|
||||
// Ie., instead of 'example.org' show something like 'e**mpl*.or*'.
|
||||
// example: false
|
||||
Obfuscate bool `form:"obfuscate" json:"obfuscate" xml:"obfuscate"`
|
||||
Obfuscate bool `form:"obfuscate" json:"obfuscate"`
|
||||
// Private comment for other admins on why this permission entry was created.
|
||||
// example: don't like 'em!!!!
|
||||
PrivateComment string `form:"private_comment" json:"private_comment" xml:"private_comment"`
|
||||
PrivateComment string `form:"private_comment" json:"private_comment"`
|
||||
// Public comment on why this permission entry was created.
|
||||
// Will be visible to requesters at /api/v1/instance/peers if this endpoint is exposed.
|
||||
// example: foss dorks 😫
|
||||
PublicComment string `form:"public_comment" json:"public_comment" xml:"public_comment"`
|
||||
PublicComment string `form:"public_comment" json:"public_comment"`
|
||||
// Permission type to create (only applies to domain permission drafts, not explicit blocks and allows).
|
||||
PermissionType string `form:"permission_type" json:"permission_type"`
|
||||
}
|
||||
|
||||
// DomainKeysExpireRequest is the form submitted as a POST to /api/v1/admin/domain_keys_expire to expire a domain's public keys.
|
||||
|
@ -92,5 +138,5 @@ type DomainPermissionRequest struct {
|
|||
// swagger:parameters domainKeysExpire
|
||||
type DomainKeysExpireRequest struct {
|
||||
// hostname/domain to expire keys for.
|
||||
Domain string `form:"domain" json:"domain" xml:"domain"`
|
||||
Domain string `form:"domain" json:"domain"`
|
||||
}
|
||||
|
|
|
@ -71,6 +71,9 @@
|
|||
|
||||
DomainPermissionExportKey = "export"
|
||||
DomainPermissionImportKey = "import"
|
||||
DomainPermissionSubscriptionIDKey = "subscription_id"
|
||||
DomainPermissionPermTypeKey = "permission_type"
|
||||
DomainPermissionDomainKey = "domain"
|
||||
|
||||
/* Admin query keys */
|
||||
|
||||
|
|
3
internal/cache/cache.go
vendored
3
internal/cache/cache.go
vendored
|
@ -74,6 +74,9 @@ func (c *Caches) Init() {
|
|||
c.initConversationLastStatusIDs()
|
||||
c.initDomainAllow()
|
||||
c.initDomainBlock()
|
||||
c.initDomainPermissionDraft()
|
||||
c.initDomainPermissionSubscription()
|
||||
c.initDomainPermissionIgnore()
|
||||
c.initEmoji()
|
||||
c.initEmojiCategory()
|
||||
c.initFilter()
|
||||
|
|
76
internal/cache/db.go
vendored
76
internal/cache/db.go
vendored
|
@ -67,6 +67,15 @@ type DBCaches struct {
|
|||
// DomainBlock provides access to the domain block database cache.
|
||||
DomainBlock *domain.Cache
|
||||
|
||||
// DomainPermissionDraft provides access to the domain permission draft database cache.
|
||||
DomainPermissionDraft StructCache[*gtsmodel.DomainPermissionDraft]
|
||||
|
||||
// DomainPermissionSubscription provides access to the domain permission subscription database cache.
|
||||
DomainPermissionSubscription StructCache[*gtsmodel.DomainPermissionSubscription]
|
||||
|
||||
// DomainPermissionIgnore provides access to the domain permission ignore database cache.
|
||||
DomainPermissionIgnore *domain.Cache
|
||||
|
||||
// Emoji provides access to the gtsmodel Emoji database cache.
|
||||
Emoji StructCache[*gtsmodel.Emoji]
|
||||
|
||||
|
@ -548,6 +557,73 @@ func (c *Caches) initDomainBlock() {
|
|||
c.DB.DomainBlock = new(domain.Cache)
|
||||
}
|
||||
|
||||
func (c *Caches) initDomainPermissionDraft() {
|
||||
// Calculate maximum cache size.
|
||||
cap := calculateResultCacheMax(
|
||||
sizeofDomainPermissionDraft(), // model in-mem size.
|
||||
config.GetCacheDomainPermissionDraftMemRation(),
|
||||
)
|
||||
|
||||
log.Infof(nil, "cache size = %d", cap)
|
||||
|
||||
copyF := func(d1 *gtsmodel.DomainPermissionDraft) *gtsmodel.DomainPermissionDraft {
|
||||
d2 := new(gtsmodel.DomainPermissionDraft)
|
||||
*d2 = *d1
|
||||
|
||||
// Don't include ptr fields that
|
||||
// will be populated separately.
|
||||
d2.CreatedByAccount = nil
|
||||
|
||||
return d2
|
||||
}
|
||||
|
||||
c.DB.DomainPermissionDraft.Init(structr.CacheConfig[*gtsmodel.DomainPermissionDraft]{
|
||||
Indices: []structr.IndexConfig{
|
||||
{Fields: "ID"},
|
||||
{Fields: "Domain", Multiple: true},
|
||||
{Fields: "SubscriptionID", Multiple: true},
|
||||
},
|
||||
MaxSize: cap,
|
||||
IgnoreErr: ignoreErrors,
|
||||
Copy: copyF,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Caches) initDomainPermissionSubscription() {
|
||||
// Calculate maximum cache size.
|
||||
cap := calculateResultCacheMax(
|
||||
sizeofDomainPermissionSubscription(), // model in-mem size.
|
||||
config.GetCacheDomainPermissionSubscriptionMemRation(),
|
||||
)
|
||||
|
||||
log.Infof(nil, "cache size = %d", cap)
|
||||
|
||||
copyF := func(d1 *gtsmodel.DomainPermissionSubscription) *gtsmodel.DomainPermissionSubscription {
|
||||
d2 := new(gtsmodel.DomainPermissionSubscription)
|
||||
*d2 = *d1
|
||||
|
||||
// Don't include ptr fields that
|
||||
// will be populated separately.
|
||||
d2.CreatedByAccount = nil
|
||||
|
||||
return d2
|
||||
}
|
||||
|
||||
c.DB.DomainPermissionSubscription.Init(structr.CacheConfig[*gtsmodel.DomainPermissionSubscription]{
|
||||
Indices: []structr.IndexConfig{
|
||||
{Fields: "ID"},
|
||||
{Fields: "URI"},
|
||||
},
|
||||
MaxSize: cap,
|
||||
IgnoreErr: ignoreErrors,
|
||||
Copy: copyF,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Caches) initDomainPermissionIgnore() {
|
||||
c.DB.DomainPermissionIgnore = new(domain.Cache)
|
||||
}
|
||||
|
||||
func (c *Caches) initEmoji() {
|
||||
// Calculate maximum cache size.
|
||||
cap := calculateResultCacheMax(
|
||||
|
|
29
internal/cache/size.go
vendored
29
internal/cache/size.go
vendored
|
@ -342,6 +342,35 @@ func sizeofConversation() uintptr {
|
|||
}))
|
||||
}
|
||||
|
||||
func sizeofDomainPermissionDraft() uintptr {
|
||||
return uintptr(size.Of(>smodel.DomainPermissionDraft{
|
||||
ID: exampleID,
|
||||
CreatedAt: exampleTime,
|
||||
UpdatedAt: exampleTime,
|
||||
PermissionType: gtsmodel.DomainPermissionBlock,
|
||||
Domain: "example.org",
|
||||
CreatedByAccountID: exampleID,
|
||||
PrivateComment: exampleTextSmall,
|
||||
PublicComment: exampleTextSmall,
|
||||
Obfuscate: util.Ptr(false),
|
||||
SubscriptionID: exampleID,
|
||||
}))
|
||||
}
|
||||
|
||||
func sizeofDomainPermissionSubscription() uintptr {
|
||||
return uintptr(size.Of(>smodel.DomainPermissionSubscription{
|
||||
ID: exampleID,
|
||||
CreatedAt: exampleTime,
|
||||
PermissionType: gtsmodel.DomainPermissionBlock,
|
||||
CreatedByAccountID: exampleID,
|
||||
URI: exampleURI,
|
||||
FetchUsername: "username",
|
||||
FetchPassword: "password",
|
||||
FetchedAt: exampleTime,
|
||||
AsDraft: util.Ptr(true),
|
||||
}))
|
||||
}
|
||||
|
||||
func sizeofEmoji() uintptr {
|
||||
return uintptr(size.Of(>smodel.Emoji{
|
||||
ID: exampleID,
|
||||
|
|
|
@ -206,6 +206,8 @@ type CacheConfiguration struct {
|
|||
ClientMemRatio float64 `name:"client-mem-ratio"`
|
||||
ConversationMemRatio float64 `name:"conversation-mem-ratio"`
|
||||
ConversationLastStatusIDsMemRatio float64 `name:"conversation-last-status-ids-mem-ratio"`
|
||||
DomainPermissionDraftMemRation float64 `name:"domain-permission-draft-mem-ratio"`
|
||||
DomainPermissionSubscriptionMemRation float64 `name:"domain-permission-subscription-mem-ratio"`
|
||||
EmojiMemRatio float64 `name:"emoji-mem-ratio"`
|
||||
EmojiCategoryMemRatio float64 `name:"emoji-category-mem-ratio"`
|
||||
FilterMemRatio float64 `name:"filter-mem-ratio"`
|
||||
|
|
|
@ -169,6 +169,8 @@
|
|||
ClientMemRatio: 0.1,
|
||||
ConversationMemRatio: 1,
|
||||
ConversationLastStatusIDsMemRatio: 2,
|
||||
DomainPermissionDraftMemRation: 0.5,
|
||||
DomainPermissionSubscriptionMemRation: 0.5,
|
||||
EmojiMemRatio: 3,
|
||||
EmojiCategoryMemRatio: 0.1,
|
||||
FilterMemRatio: 0.5,
|
||||
|
|
|
@ -3106,6 +3106,68 @@ func SetCacheConversationLastStatusIDsMemRatio(v float64) {
|
|||
global.SetCacheConversationLastStatusIDsMemRatio(v)
|
||||
}
|
||||
|
||||
// GetCacheDomainPermissionDraftMemRation safely fetches the Configuration value for state's 'Cache.DomainPermissionDraftMemRation' field
|
||||
func (st *ConfigState) GetCacheDomainPermissionDraftMemRation() (v float64) {
|
||||
st.mutex.RLock()
|
||||
v = st.config.Cache.DomainPermissionDraftMemRation
|
||||
st.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// SetCacheDomainPermissionDraftMemRation safely sets the Configuration value for state's 'Cache.DomainPermissionDraftMemRation' field
|
||||
func (st *ConfigState) SetCacheDomainPermissionDraftMemRation(v float64) {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.config.Cache.DomainPermissionDraftMemRation = v
|
||||
st.reloadToViper()
|
||||
}
|
||||
|
||||
// CacheDomainPermissionDraftMemRationFlag returns the flag name for the 'Cache.DomainPermissionDraftMemRation' field
|
||||
func CacheDomainPermissionDraftMemRationFlag() string {
|
||||
return "cache-domain-permission-draft-mem-ratio"
|
||||
}
|
||||
|
||||
// GetCacheDomainPermissionDraftMemRation safely fetches the value for global configuration 'Cache.DomainPermissionDraftMemRation' field
|
||||
func GetCacheDomainPermissionDraftMemRation() float64 {
|
||||
return global.GetCacheDomainPermissionDraftMemRation()
|
||||
}
|
||||
|
||||
// SetCacheDomainPermissionDraftMemRation safely sets the value for global configuration 'Cache.DomainPermissionDraftMemRation' field
|
||||
func SetCacheDomainPermissionDraftMemRation(v float64) {
|
||||
global.SetCacheDomainPermissionDraftMemRation(v)
|
||||
}
|
||||
|
||||
// GetCacheDomainPermissionSubscriptionMemRation safely fetches the Configuration value for state's 'Cache.DomainPermissionSubscriptionMemRation' field
|
||||
func (st *ConfigState) GetCacheDomainPermissionSubscriptionMemRation() (v float64) {
|
||||
st.mutex.RLock()
|
||||
v = st.config.Cache.DomainPermissionSubscriptionMemRation
|
||||
st.mutex.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// SetCacheDomainPermissionSubscriptionMemRation safely sets the Configuration value for state's 'Cache.DomainPermissionSubscriptionMemRation' field
|
||||
func (st *ConfigState) SetCacheDomainPermissionSubscriptionMemRation(v float64) {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.config.Cache.DomainPermissionSubscriptionMemRation = v
|
||||
st.reloadToViper()
|
||||
}
|
||||
|
||||
// CacheDomainPermissionSubscriptionMemRationFlag returns the flag name for the 'Cache.DomainPermissionSubscriptionMemRation' field
|
||||
func CacheDomainPermissionSubscriptionMemRationFlag() string {
|
||||
return "cache-domain-permission-subscription-mem-ratio"
|
||||
}
|
||||
|
||||
// GetCacheDomainPermissionSubscriptionMemRation safely fetches the value for global configuration 'Cache.DomainPermissionSubscriptionMemRation' field
|
||||
func GetCacheDomainPermissionSubscriptionMemRation() float64 {
|
||||
return global.GetCacheDomainPermissionSubscriptionMemRation()
|
||||
}
|
||||
|
||||
// SetCacheDomainPermissionSubscriptionMemRation safely sets the value for global configuration 'Cache.DomainPermissionSubscriptionMemRation' field
|
||||
func SetCacheDomainPermissionSubscriptionMemRation(v float64) {
|
||||
global.SetCacheDomainPermissionSubscriptionMemRation(v)
|
||||
}
|
||||
|
||||
// GetCacheEmojiMemRatio safely fetches the Configuration value for state's 'Cache.EmojiMemRatio' field
|
||||
func (st *ConfigState) GetCacheEmojiMemRatio() (v float64) {
|
||||
st.mutex.RLock()
|
||||
|
|
|
@ -19,12 +19,18 @@
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/url"
|
||||
"slices"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/state"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
"github.com/uptrace/bun"
|
||||
|
@ -328,3 +334,701 @@ func (d *domainDB) AreURIsBlocked(ctx context.Context, uris []*url.URL) (bool, e
|
|||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) getDomainPermissionDraft(
|
||||
ctx context.Context,
|
||||
lookup string,
|
||||
dbQuery func(*gtsmodel.DomainPermissionDraft) error,
|
||||
keyParts ...any,
|
||||
) (*gtsmodel.DomainPermissionDraft, error) {
|
||||
// Fetch perm draft from database cache with loader callback.
|
||||
permDraft, err := d.state.Caches.DB.DomainPermissionDraft.LoadOne(
|
||||
lookup,
|
||||
// Only called if not cached.
|
||||
func() (*gtsmodel.DomainPermissionDraft, error) {
|
||||
var permDraft gtsmodel.DomainPermissionDraft
|
||||
if err := dbQuery(&permDraft); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &permDraft, nil
|
||||
},
|
||||
keyParts...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gtscontext.Barebones(ctx) {
|
||||
// No need to fully populate.
|
||||
return permDraft, nil
|
||||
}
|
||||
|
||||
if permDraft.CreatedByAccount == nil {
|
||||
// Not set, fetch from database.
|
||||
permDraft.CreatedByAccount, err = d.state.DB.GetAccountByID(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
permDraft.CreatedByAccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error populating created by account: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return permDraft, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionDraftByID(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (*gtsmodel.DomainPermissionDraft, error) {
|
||||
return d.getDomainPermissionDraft(
|
||||
ctx,
|
||||
"ID",
|
||||
func(permDraft *gtsmodel.DomainPermissionDraft) error {
|
||||
return d.db.
|
||||
NewSelect().
|
||||
Model(permDraft).
|
||||
Where("? = ?", bun.Ident("domain_permission_draft.id"), id).
|
||||
Scan(ctx)
|
||||
},
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionDrafts(
|
||||
ctx context.Context,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
permSubID string,
|
||||
domain string,
|
||||
page *paging.Page,
|
||||
) (
|
||||
[]*gtsmodel.DomainPermissionDraft,
|
||||
error,
|
||||
) {
|
||||
var (
|
||||
// Get paging params.
|
||||
minID = page.GetMin()
|
||||
maxID = page.GetMax()
|
||||
limit = page.GetLimit()
|
||||
order = page.GetOrder()
|
||||
|
||||
// Make educated guess for slice size
|
||||
permDraftIDs = make([]string, 0, limit)
|
||||
)
|
||||
|
||||
q := d.db.
|
||||
NewSelect().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_drafts"),
|
||||
bun.Ident("domain_permission_draft"),
|
||||
).
|
||||
// Select only IDs from table
|
||||
Column("domain_permission_draft.id")
|
||||
|
||||
// Return only items with id
|
||||
// lower than provided maxID.
|
||||
if maxID != "" {
|
||||
q = q.Where(
|
||||
"? < ?",
|
||||
bun.Ident("domain_permission_draft.id"),
|
||||
maxID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with id
|
||||
// greater than provided minID.
|
||||
if minID != "" {
|
||||
q = q.Where(
|
||||
"? > ?",
|
||||
bun.Ident("domain_permission_draft.id"),
|
||||
minID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with
|
||||
// given permission type.
|
||||
if permType != gtsmodel.DomainPermissionUnknown {
|
||||
q = q.Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_draft.permission_type"),
|
||||
permType,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with
|
||||
// given subscription ID.
|
||||
if permSubID != "" {
|
||||
q = q.Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_draft.subscription_id"),
|
||||
permSubID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items
|
||||
// with given domain.
|
||||
if domain != "" {
|
||||
var err error
|
||||
|
||||
// Normalize domain as punycode.
|
||||
domain, err = util.Punify(domain)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error punifying domain %s: %w", domain, err)
|
||||
}
|
||||
|
||||
q = q.Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_draft.domain"),
|
||||
domain,
|
||||
)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
// Limit amount of
|
||||
// items returned.
|
||||
q = q.Limit(limit)
|
||||
}
|
||||
|
||||
if order == paging.OrderAscending {
|
||||
// Page up.
|
||||
q = q.OrderExpr(
|
||||
"? ASC",
|
||||
bun.Ident("domain_permission_draft.id"),
|
||||
)
|
||||
} else {
|
||||
// Page down.
|
||||
q = q.OrderExpr(
|
||||
"? DESC",
|
||||
bun.Ident("domain_permission_draft.id"),
|
||||
)
|
||||
}
|
||||
|
||||
if err := q.Scan(ctx, &permDraftIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Catch case of no items early
|
||||
if len(permDraftIDs) == 0 {
|
||||
return nil, db.ErrNoEntries
|
||||
}
|
||||
|
||||
// If we're paging up, we still want items
|
||||
// to be sorted by ID desc, so reverse slice.
|
||||
if order == paging.OrderAscending {
|
||||
slices.Reverse(permDraftIDs)
|
||||
}
|
||||
|
||||
// Allocate return slice (will be at most len permDraftIDs)
|
||||
permDrafts := make([]*gtsmodel.DomainPermissionDraft, 0, len(permDraftIDs))
|
||||
for _, id := range permDraftIDs {
|
||||
permDraft, err := d.GetDomainPermissionDraftByID(ctx, id)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting domain permission draft %q: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append to return slice
|
||||
permDrafts = append(permDrafts, permDraft)
|
||||
}
|
||||
|
||||
return permDrafts, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) PutDomainPermissionDraft(
|
||||
ctx context.Context,
|
||||
permDraft *gtsmodel.DomainPermissionDraft,
|
||||
) error {
|
||||
var err error
|
||||
|
||||
// Normalize the domain as punycode
|
||||
permDraft.Domain, err = util.Punify(permDraft.Domain)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error punifying domain %s: %w", permDraft.Domain, err)
|
||||
}
|
||||
|
||||
return d.state.Caches.DB.DomainPermissionDraft.Store(
|
||||
permDraft,
|
||||
func() error {
|
||||
_, err := d.db.
|
||||
NewInsert().
|
||||
Model(permDraft).
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (d *domainDB) DeleteDomainPermissionDraft(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) error {
|
||||
// Delete the permDraft from DB.
|
||||
q := d.db.NewDelete().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_drafts"),
|
||||
bun.Ident("domain_permission_draft"),
|
||||
).
|
||||
Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_draft.id"),
|
||||
id,
|
||||
)
|
||||
|
||||
_, err := q.Exec(ctx)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Invalidate any cached model by ID.
|
||||
d.state.Caches.DB.DomainPermissionDraft.Invalidate("ID", id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *domainDB) getDomainPermissionSubscription(
|
||||
ctx context.Context,
|
||||
lookup string,
|
||||
dbQuery func(*gtsmodel.DomainPermissionSubscription) error,
|
||||
keyParts ...any,
|
||||
) (*gtsmodel.DomainPermissionSubscription, error) {
|
||||
// Fetch perm subscription from database cache with loader callback.
|
||||
permSub, err := d.state.Caches.DB.DomainPermissionSubscription.LoadOne(
|
||||
lookup,
|
||||
// Only called if not cached.
|
||||
func() (*gtsmodel.DomainPermissionSubscription, error) {
|
||||
var permSub gtsmodel.DomainPermissionSubscription
|
||||
if err := dbQuery(&permSub); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &permSub, nil
|
||||
},
|
||||
keyParts...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gtscontext.Barebones(ctx) {
|
||||
// No need to fully populate.
|
||||
return permSub, nil
|
||||
}
|
||||
|
||||
if permSub.CreatedByAccount == nil {
|
||||
// Not set, fetch from database.
|
||||
permSub.CreatedByAccount, err = d.state.DB.GetAccountByID(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
permSub.CreatedByAccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error populating created by account: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return permSub, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionSubscriptionByID(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (*gtsmodel.DomainPermissionSubscription, error) {
|
||||
return d.getDomainPermissionSubscription(
|
||||
ctx,
|
||||
"ID",
|
||||
func(permSub *gtsmodel.DomainPermissionSubscription) error {
|
||||
return d.db.
|
||||
NewSelect().
|
||||
Model(permSub).
|
||||
Where("? = ?", bun.Ident("domain_permission_subscription.id"), id).
|
||||
Scan(ctx)
|
||||
},
|
||||
id,
|
||||
)
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionSubscriptions(
|
||||
ctx context.Context,
|
||||
permType *gtsmodel.DomainPermissionType,
|
||||
page *paging.Page,
|
||||
) (
|
||||
[]*gtsmodel.DomainPermissionSubscription,
|
||||
error,
|
||||
) {
|
||||
var (
|
||||
// Get paging params.
|
||||
minID = page.GetMin()
|
||||
maxID = page.GetMax()
|
||||
limit = page.GetLimit()
|
||||
order = page.GetOrder()
|
||||
|
||||
// Make educated guess for slice size
|
||||
permSubIDs = make([]string, 0, limit)
|
||||
)
|
||||
|
||||
q := d.db.
|
||||
NewSelect().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_subscriptions"),
|
||||
bun.Ident("domain_permission_subscription"),
|
||||
).
|
||||
// Select only IDs from table
|
||||
Column("domain_permission_subscription.id")
|
||||
|
||||
// Return only items with id
|
||||
// lower than provided maxID.
|
||||
if maxID != "" {
|
||||
q = q.Where(
|
||||
"? < ?",
|
||||
bun.Ident("domain_permission_subscription.id"),
|
||||
maxID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with id
|
||||
// greater than provided minID.
|
||||
if minID != "" {
|
||||
q = q.Where(
|
||||
"? > ?",
|
||||
bun.Ident("domain_permission_subscription.id"),
|
||||
minID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with
|
||||
// given subscription ID.
|
||||
if permType != nil {
|
||||
q = q.Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_subscription.permission_type"),
|
||||
*permType,
|
||||
)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
// Limit amount of
|
||||
// items returned.
|
||||
q = q.Limit(limit)
|
||||
}
|
||||
|
||||
if order == paging.OrderAscending {
|
||||
// Page up.
|
||||
q = q.OrderExpr(
|
||||
"? ASC",
|
||||
bun.Ident("domain_permission_subscription.id"),
|
||||
)
|
||||
} else {
|
||||
// Page down.
|
||||
q = q.OrderExpr(
|
||||
"? DESC",
|
||||
bun.Ident("domain_permission_subscription.id"),
|
||||
)
|
||||
}
|
||||
|
||||
if err := q.Scan(ctx, &permSubIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Catch case of no items early
|
||||
if len(permSubIDs) == 0 {
|
||||
return nil, db.ErrNoEntries
|
||||
}
|
||||
|
||||
// If we're paging up, we still want items
|
||||
// to be sorted by ID desc, so reverse slice.
|
||||
if order == paging.OrderAscending {
|
||||
slices.Reverse(permSubIDs)
|
||||
}
|
||||
|
||||
// Allocate return slice (will be at most len permSubIDs).
|
||||
permSubs := make([]*gtsmodel.DomainPermissionSubscription, 0, len(permSubIDs))
|
||||
for _, id := range permSubIDs {
|
||||
permSub, err := d.GetDomainPermissionSubscriptionByID(ctx, id)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting domain permission subscription %q: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append to return slice
|
||||
permSubs = append(permSubs, permSub)
|
||||
}
|
||||
|
||||
return permSubs, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) PutDomainPermissionSubscription(
|
||||
ctx context.Context,
|
||||
permSubscription *gtsmodel.DomainPermissionSubscription,
|
||||
) error {
|
||||
return d.state.Caches.DB.DomainPermissionSubscription.Store(
|
||||
permSubscription,
|
||||
func() error {
|
||||
_, err := d.db.
|
||||
NewInsert().
|
||||
Model(permSubscription).
|
||||
Exec(ctx)
|
||||
return err
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (d *domainDB) DeleteDomainPermissionSubscription(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) error {
|
||||
// Delete the permSub from DB.
|
||||
q := d.db.NewDelete().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_subscriptions"),
|
||||
bun.Ident("domain_permission_subscription"),
|
||||
).
|
||||
Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_subscription.id"),
|
||||
id,
|
||||
)
|
||||
|
||||
_, err := q.Exec(ctx)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Invalidate any cached model by ID.
|
||||
d.state.Caches.DB.DomainPermissionSubscription.Invalidate("ID", id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *domainDB) PutDomainPermissionIgnore(
|
||||
ctx context.Context,
|
||||
ignore *gtsmodel.DomainPermissionIgnore,
|
||||
) error {
|
||||
// Normalize the domain as punycode
|
||||
var err error
|
||||
ignore.Domain, err = util.Punify(ignore.Domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Attempt to store domain perm ignore in DB
|
||||
if _, err := d.db.NewInsert().
|
||||
Model(ignore).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear the domain perm ignore cache (for later reload)
|
||||
d.state.Caches.DB.DomainPermissionIgnore.Clear()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *domainDB) IsDomainPermissionIgnored(ctx context.Context, domain string) (bool, error) {
|
||||
// Normalize the domain as punycode
|
||||
domain, err := util.Punify(domain)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check if our host and given domain are equal
|
||||
// or part of the same second-level domain; we
|
||||
// always ignore such perms as creating blocks
|
||||
// or allows in such cases may break things.
|
||||
if dns.CompareDomainName(domain, config.GetHost()) >= 2 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Func to scan list of all
|
||||
// ignored domain perms from DB.
|
||||
loadF := func() ([]string, error) {
|
||||
var domains []string
|
||||
|
||||
if err := d.db.
|
||||
NewSelect().
|
||||
Table("domain_ignores").
|
||||
Column("domain").
|
||||
Scan(ctx, &domains); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return domains, nil
|
||||
}
|
||||
|
||||
// Check the cache for a domain perm ignore,
|
||||
// hydrating the cache with loadF if necessary.
|
||||
return d.state.Caches.DB.DomainPermissionIgnore.Matches(domain, loadF)
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionIgnoreByID(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (*gtsmodel.DomainPermissionIgnore, error) {
|
||||
ignore := new(gtsmodel.DomainPermissionIgnore)
|
||||
|
||||
q := d.db.
|
||||
NewSelect().
|
||||
Model(ignore).
|
||||
Where("? = ?", bun.Ident("domain_permission_ignore.id"), id)
|
||||
if err := q.Scan(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gtscontext.Barebones(ctx) {
|
||||
// No need to fully populate.
|
||||
return ignore, nil
|
||||
}
|
||||
|
||||
if ignore.CreatedByAccount == nil {
|
||||
// Not set, fetch from database.
|
||||
var err error
|
||||
ignore.CreatedByAccount, err = d.state.DB.GetAccountByID(
|
||||
gtscontext.SetBarebones(ctx),
|
||||
ignore.CreatedByAccountID,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, gtserror.Newf("error populating created by account: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return ignore, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) GetDomainPermissionIgnores(
|
||||
ctx context.Context,
|
||||
permType *gtsmodel.DomainPermissionType,
|
||||
page *paging.Page,
|
||||
) (
|
||||
[]*gtsmodel.DomainPermissionIgnore,
|
||||
error,
|
||||
) {
|
||||
var (
|
||||
// Get paging params.
|
||||
minID = page.GetMin()
|
||||
maxID = page.GetMax()
|
||||
limit = page.GetLimit()
|
||||
order = page.GetOrder()
|
||||
|
||||
// Make educated guess for slice size
|
||||
ignoreIDs = make([]string, 0, limit)
|
||||
)
|
||||
|
||||
q := d.db.
|
||||
NewSelect().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_ignores"),
|
||||
bun.Ident("domain_permission_ignore"),
|
||||
).
|
||||
// Select only IDs from table
|
||||
Column("domain_permission_ignore.id")
|
||||
|
||||
// Return only items with id
|
||||
// lower than provided maxID.
|
||||
if maxID != "" {
|
||||
q = q.Where(
|
||||
"? < ?",
|
||||
bun.Ident("domain_permission_ignore.id"),
|
||||
maxID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with id
|
||||
// greater than provided minID.
|
||||
if minID != "" {
|
||||
q = q.Where(
|
||||
"? > ?",
|
||||
bun.Ident("domain_permission_ignore.id"),
|
||||
minID,
|
||||
)
|
||||
}
|
||||
|
||||
// Return only items with
|
||||
// given subscription ID.
|
||||
if permType != nil {
|
||||
q = q.Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_ignore.permission_type"),
|
||||
*permType,
|
||||
)
|
||||
}
|
||||
|
||||
if limit > 0 {
|
||||
// Limit amount of
|
||||
// items returned.
|
||||
q = q.Limit(limit)
|
||||
}
|
||||
|
||||
if order == paging.OrderAscending {
|
||||
// Page up.
|
||||
q = q.OrderExpr(
|
||||
"? ASC",
|
||||
bun.Ident("domain_permission_ignore.id"),
|
||||
)
|
||||
} else {
|
||||
// Page down.
|
||||
q = q.OrderExpr(
|
||||
"? DESC",
|
||||
bun.Ident("domain_permission_ignore.id"),
|
||||
)
|
||||
}
|
||||
|
||||
if err := q.Scan(ctx, &ignoreIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Catch case of no items early
|
||||
if len(ignoreIDs) == 0 {
|
||||
return nil, db.ErrNoEntries
|
||||
}
|
||||
|
||||
// If we're paging up, we still want items
|
||||
// to be sorted by ID desc, so reverse slice.
|
||||
if order == paging.OrderAscending {
|
||||
slices.Reverse(ignoreIDs)
|
||||
}
|
||||
|
||||
// Allocate return slice (will be at most len permSubIDs).
|
||||
ignores := make([]*gtsmodel.DomainPermissionIgnore, 0, len(ignoreIDs))
|
||||
for _, id := range ignoreIDs {
|
||||
ignore, err := d.GetDomainPermissionIgnoreByID(ctx, id)
|
||||
if err != nil {
|
||||
log.Errorf(ctx, "error getting domain permission ignore %q: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Append to return slice
|
||||
ignores = append(ignores, ignore)
|
||||
}
|
||||
|
||||
return ignores, nil
|
||||
}
|
||||
|
||||
func (d *domainDB) DeleteDomainPermissionIgnore(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) error {
|
||||
// Delete the permSub from DB.
|
||||
q := d.db.NewDelete().
|
||||
TableExpr(
|
||||
"? AS ?",
|
||||
bun.Ident("domain_permission_ignores"),
|
||||
bun.Ident("domain_permission_ignore"),
|
||||
).
|
||||
Where(
|
||||
"? = ?",
|
||||
bun.Ident("domain_permission_ignore.id"),
|
||||
id,
|
||||
)
|
||||
|
||||
_, err := q.Exec(ctx)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear the domain perm ignore cache (for later reload)
|
||||
d.state.Caches.DB.DomainPermissionIgnore.Clear()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -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/>.
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
func init() {
|
||||
up := func(ctx context.Context, db *bun.DB) error {
|
||||
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
|
||||
// Create `domain_permission_drafts`.
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model((*gtsmodel.DomainPermissionDraft)(nil)).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create `domain_permission_subscriptions`.
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model((*gtsmodel.DomainPermissionSubscription)(nil)).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create `domain_permission_ignores`.
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model((*gtsmodel.DomainPermissionIgnore)(nil)).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes. Indices. Indie sexes.
|
||||
for table, indexes := range map[string]map[string][]string{
|
||||
"domain_permission_drafts": {
|
||||
"domain_permission_drafts_domain_idx": {"domain"},
|
||||
"domain_permission_drafts_subscription_id_idx": {"subscription_id"},
|
||||
},
|
||||
"domain_permission_subscriptions": {
|
||||
"domain_permission_subscriptions_permission_type_idx": {"permission_type"},
|
||||
},
|
||||
} {
|
||||
for index, columns := range indexes {
|
||||
if _, err := tx.
|
||||
NewCreateIndex().
|
||||
Table(table).
|
||||
Index(index).
|
||||
Column(columns...).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
down := func(ctx context.Context, db *bun.DB) error {
|
||||
return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := Migrations.Register(up, down); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
"net/url"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// Domain contains DB functions related to domains and domain blocks.
|
||||
|
@ -78,4 +79,48 @@ type Domain interface {
|
|||
// AreURIsBlocked calls IsURIBlocked for each URI.
|
||||
// Will return true if even one of the given URIs is blocked.
|
||||
AreURIsBlocked(ctx context.Context, uris []*url.URL) (bool, error)
|
||||
|
||||
/*
|
||||
Domain permission draft stuff.
|
||||
*/
|
||||
|
||||
// GetDomainPermissionDraftByID gets one DomainPermissionDraft with the given ID.
|
||||
GetDomainPermissionDraftByID(ctx context.Context, id string) (*gtsmodel.DomainPermissionDraft, error)
|
||||
|
||||
// GetDomainPermissionDrafts returns a page of
|
||||
// DomainPermissionDrafts using the given parameters.
|
||||
GetDomainPermissionDrafts(
|
||||
ctx context.Context,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
permSubID string,
|
||||
domain string,
|
||||
page *paging.Page,
|
||||
) ([]*gtsmodel.DomainPermissionDraft, error)
|
||||
|
||||
// PutDomainPermissionDraft stores one DomainPermissionDraft.
|
||||
PutDomainPermissionDraft(ctx context.Context, permDraft *gtsmodel.DomainPermissionDraft) error
|
||||
|
||||
// DeleteDomainPermissionDraft deletes one DomainPermissionDraft with the given id.
|
||||
DeleteDomainPermissionDraft(ctx context.Context, id string) error
|
||||
|
||||
/*
|
||||
Domain permission subscription stuff.
|
||||
*/
|
||||
|
||||
// GetDomainPermissionSubscriptionByID gets one DomainPermissionSubscription with the given ID.
|
||||
GetDomainPermissionSubscriptionByID(ctx context.Context, id string) (*gtsmodel.DomainPermissionSubscription, error)
|
||||
|
||||
// GetDomainPermissionSubscriptions returns a page of
|
||||
// DomainPermissionSubscriptions using the given parameters.
|
||||
GetDomainPermissionSubscriptions(
|
||||
ctx context.Context,
|
||||
permType *gtsmodel.DomainPermissionType,
|
||||
page *paging.Page,
|
||||
) ([]*gtsmodel.DomainPermissionSubscription, error)
|
||||
|
||||
// PutDomainPermissionSubscription stores one DomainPermissionSubscription.
|
||||
PutDomainPermissionSubscription(ctx context.Context, permSub *gtsmodel.DomainPermissionSubscription) error
|
||||
|
||||
// DeleteDomainPermissionSubscription deletes one DomainPermissionSubscription with the given id.
|
||||
DeleteDomainPermissionSubscription(ctx context.Context, id string) error
|
||||
}
|
||||
|
|
78
internal/gtsmodel/domainpermissiondraft.go
Normal file
78
internal/gtsmodel/domainpermissiondraft.go
Normal file
|
@ -0,0 +1,78 @@
|
|||
// 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 gtsmodel
|
||||
|
||||
import "time"
|
||||
|
||||
type DomainPermissionDraft struct {
|
||||
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.
|
||||
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was last updated.
|
||||
PermissionType DomainPermissionType `bun:",notnull,unique:domain_permission_drafts_permission_type_domain_subscription_id_uniq"` // Permission type of the draft.
|
||||
Domain string `bun:",nullzero,notnull,unique:domain_permission_drafts_permission_type_domain_subscription_id_uniq"` // Domain to block or allow. Eg. 'whatever.com'.
|
||||
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this subscription.
|
||||
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
||||
PrivateComment string `bun:",nullzero"` // Private comment on this perm, viewable to admins.
|
||||
PublicComment string `bun:",nullzero"` // Public comment on this perm, viewable (optionally) by everyone.
|
||||
Obfuscate *bool `bun:",nullzero,notnull,default:false"` // Obfuscate domain name when displaying it publicly.
|
||||
SubscriptionID string `bun:"type:CHAR(26),nullzero,unique:domain_permission_drafts_permission_type_domain_subscription_id_uniq"` // ID of the subscription that created this draft, if any.
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetID() string {
|
||||
return d.ID
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetCreatedAt() time.Time {
|
||||
return d.CreatedAt
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetUpdatedAt() time.Time {
|
||||
return d.UpdatedAt
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetDomain() string {
|
||||
return d.Domain
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetCreatedByAccountID() string {
|
||||
return d.CreatedByAccountID
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetCreatedByAccount() *Account {
|
||||
return d.CreatedByAccount
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetPrivateComment() string {
|
||||
return d.PrivateComment
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetPublicComment() string {
|
||||
return d.PublicComment
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetObfuscate() *bool {
|
||||
return d.Obfuscate
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetSubscriptionID() string {
|
||||
return d.SubscriptionID
|
||||
}
|
||||
|
||||
func (d *DomainPermissionDraft) GetType() DomainPermissionType {
|
||||
return DomainPermissionBlock
|
||||
}
|
32
internal/gtsmodel/domainpermissionignore.go
Normal file
32
internal/gtsmodel/domainpermissionignore.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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 gtsmodel
|
||||
|
||||
import "time"
|
||||
|
||||
// DomainPermissionIgnore represents one domain that should be ignored
|
||||
// when domain permission (ignores) are created from subscriptions.
|
||||
type DomainPermissionIgnore struct {
|
||||
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.
|
||||
PermissionType DomainPermissionType `bun:",notnull,unique:domain_permission_ignores_permission_type_domain_uniq"` // Permission type of the ignore.
|
||||
Domain string `bun:",nullzero,notnull,unique:domain_permission_ignores_permission_type_domain_uniq"` // Domain to ignore. Eg. 'whatever.com'.
|
||||
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this ignore.
|
||||
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
||||
PrivateComment string `bun:",nullzero"` // Private comment on this ignore, viewable to admins.
|
||||
}
|
38
internal/gtsmodel/domainpermissionsubscription.go
Normal file
38
internal/gtsmodel/domainpermissionsubscription.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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 gtsmodel
|
||||
|
||||
import "time"
|
||||
|
||||
type DomainPermissionSubscription struct {
|
||||
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.
|
||||
Title string `bun:",nullzero"` // Moderator-set title for this list.
|
||||
PermissionType DomainPermissionType `bun:",notnull"` // Permission type of the subscription.
|
||||
AsDraft *bool `bun:",nullzero,notnull,default:true"` // Create domain permission entries resulting from this subscription as drafts.
|
||||
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this subscription.
|
||||
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
||||
ContentType string `bun:",nullzero,notnull"` // Content type to expect from the URI.
|
||||
URI string `bun:",unique,nullzero,notnull"` // URI of the domain permission list.
|
||||
FetchUsername string `bun:",nullzero"` // Username to send when doing a GET of URI using basic auth.
|
||||
FetchPassword string `bun:",nullzero"` // Password to send when doing a GET of URI using basic auth.
|
||||
FetchedAt time.Time `bun:"type:timestamptz,nullzero"` // Time when fetch of URI was last attempted.
|
||||
IsError *bool `bun:",nullzero,notnull,default:false"` // True if last fetch attempt of URI resulted in an error.
|
||||
Error string `bun:",nullzero"` // If IsError=true, this field contains the error resulting from the attempted fetch.
|
||||
Count uint64 `bun:""` // Count of domain permission entries discovered at URI.
|
||||
}
|
|
@ -31,24 +31,6 @@
|
|||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
// apiDomainPerm is a cheeky shortcut for returning
|
||||
// the API version of the given domain permission
|
||||
// (*gtsmodel.DomainBlock or *gtsmodel.DomainAllow),
|
||||
// or an appropriate error if something goes wrong.
|
||||
func (p *Processor) apiDomainPerm(
|
||||
ctx context.Context,
|
||||
domainPermission gtsmodel.DomainPermission,
|
||||
export bool,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
apiDomainPerm, err := p.converter.DomainPermToAPIDomainPerm(ctx, domainPermission, export)
|
||||
if err != nil {
|
||||
err := gtserror.NewfAt(3, "error converting domain permission to api model: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return apiDomainPerm, nil
|
||||
}
|
||||
|
||||
// DomainPermissionCreate creates an instance-level permission
|
||||
// targeting the given domain, and then processes any side
|
||||
// effects of the permission creation.
|
||||
|
@ -61,7 +43,7 @@ func (p *Processor) apiDomainPerm(
|
|||
// from this call, and/or an error if something goes wrong.
|
||||
func (p *Processor) DomainPermissionCreate(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
adminAcct *gtsmodel.Account,
|
||||
domain string,
|
||||
obfuscate bool,
|
||||
|
@ -69,7 +51,7 @@ func (p *Processor) DomainPermissionCreate(
|
|||
privateComment string,
|
||||
subscriptionID string,
|
||||
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
||||
switch permissionType {
|
||||
switch permType {
|
||||
|
||||
// Explicitly block a domain.
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
|
@ -97,7 +79,7 @@ func (p *Processor) DomainPermissionCreate(
|
|||
|
||||
// Weeping, roaring, red-faced.
|
||||
default:
|
||||
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
||||
return nil, "", gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
}
|
||||
|
@ -109,11 +91,11 @@ func (p *Processor) DomainPermissionCreate(
|
|||
// action resulting from this call, and/or an error if something goes wrong.
|
||||
func (p *Processor) DomainPermissionDelete(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
adminAcct *gtsmodel.Account,
|
||||
domainBlockID string,
|
||||
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
||||
switch permissionType {
|
||||
switch permType {
|
||||
|
||||
// Delete explicit domain block.
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
|
@ -134,7 +116,7 @@ func (p *Processor) DomainPermissionDelete(
|
|||
// You do the hokey-cokey and you turn
|
||||
// around, that's what it's all about.
|
||||
default:
|
||||
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
||||
return nil, "", gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
}
|
||||
|
@ -152,14 +134,14 @@ func (p *Processor) DomainPermissionDelete(
|
|||
// as they wish.
|
||||
func (p *Processor) DomainPermissionsImport(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
account *gtsmodel.Account,
|
||||
domainsF *multipart.FileHeader,
|
||||
) (*apimodel.MultiStatus, gtserror.WithCode) {
|
||||
// Ensure known permission type.
|
||||
if permissionType != gtsmodel.DomainPermissionBlock &&
|
||||
permissionType != gtsmodel.DomainPermissionAllow {
|
||||
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||
if permType != gtsmodel.DomainPermissionBlock &&
|
||||
permType != gtsmodel.DomainPermissionAllow {
|
||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
@ -201,7 +183,7 @@ func (p *Processor) DomainPermissionsImport(
|
|||
|
||||
domainPerm, _, errWithCode = p.DomainPermissionCreate(
|
||||
ctx,
|
||||
permissionType,
|
||||
permType,
|
||||
account,
|
||||
domain,
|
||||
obfuscate,
|
||||
|
@ -240,7 +222,7 @@ func (p *Processor) DomainPermissionsImport(
|
|||
// to an export.
|
||||
func (p *Processor) DomainPermissionsGet(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
account *gtsmodel.Account,
|
||||
export bool,
|
||||
) ([]*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
|
@ -249,7 +231,7 @@ func (p *Processor) DomainPermissionsGet(
|
|||
err error
|
||||
)
|
||||
|
||||
switch permissionType {
|
||||
switch permType {
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
var blocks []*gtsmodel.DomainBlock
|
||||
|
||||
|
@ -279,7 +261,7 @@ func (p *Processor) DomainPermissionsGet(
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
err := gtserror.Newf("error getting %ss: %w", permissionType.String(), err)
|
||||
err := gtserror.Newf("error getting %ss: %w", permType.String(), err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
@ -303,7 +285,7 @@ func (p *Processor) DomainPermissionsGet(
|
|||
// suitable for writing out to an export.
|
||||
func (p *Processor) DomainPermissionGet(
|
||||
ctx context.Context,
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
id string,
|
||||
export bool,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
|
@ -312,7 +294,7 @@ func (p *Processor) DomainPermissionGet(
|
|||
err error
|
||||
)
|
||||
|
||||
switch permissionType {
|
||||
switch permType {
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
domainPerm, err = p.state.DB.GetDomainBlockByID(ctx, id)
|
||||
case gtsmodel.DomainPermissionAllow:
|
||||
|
@ -323,11 +305,11 @@ func (p *Processor) DomainPermissionGet(
|
|||
|
||||
if err != nil {
|
||||
if errors.Is(err, db.ErrNoEntries) {
|
||||
err = fmt.Errorf("no domain %s exists with id %s", permissionType.String(), id)
|
||||
err = fmt.Errorf("no domain %s exists with id %s", permType.String(), id)
|
||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||
}
|
||||
|
||||
err = gtserror.Newf("error getting domain %s with id %s: %w", permissionType.String(), id, err)
|
||||
err = gtserror.Newf("error getting domain %s with id %s: %w", permType.String(), id, err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ type domainPermAction struct {
|
|||
|
||||
// Type of permission
|
||||
// to create or delete.
|
||||
permissionType gtsmodel.DomainPermissionType
|
||||
permType gtsmodel.DomainPermissionType
|
||||
|
||||
// Domain to target
|
||||
// with the permission.
|
||||
|
@ -89,9 +89,9 @@ func (suite *DomainBlockTestSuite) runDomainPermTest(t domainPermTest) {
|
|||
var actionID string
|
||||
switch action.createOrDelete {
|
||||
case "create":
|
||||
_, actionID = suite.createDomainPerm(action.permissionType, action.domain)
|
||||
_, actionID = suite.createDomainPerm(action.permType, action.domain)
|
||||
case "delete":
|
||||
_, actionID = suite.deleteDomainPerm(action.permissionType, action.domain)
|
||||
_, actionID = suite.deleteDomainPerm(action.permType, action.domain)
|
||||
default:
|
||||
panic("createOrDelete was not 'create' or 'delete'")
|
||||
}
|
||||
|
@ -118,16 +118,16 @@ func (suite *DomainBlockTestSuite) runDomainPermTest(t domainPermTest) {
|
|||
}
|
||||
}
|
||||
|
||||
// create given permissionType with default values.
|
||||
// create given permType with default values.
|
||||
func (suite *DomainBlockTestSuite) createDomainPerm(
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
domain string,
|
||||
) (*apimodel.DomainPermission, string) {
|
||||
ctx := context.Background()
|
||||
|
||||
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionCreate(
|
||||
ctx,
|
||||
permissionType,
|
||||
permType,
|
||||
suite.testAccounts["admin_account"],
|
||||
domain,
|
||||
false,
|
||||
|
@ -144,7 +144,7 @@ func (suite *DomainBlockTestSuite) createDomainPerm(
|
|||
|
||||
// delete given permission type.
|
||||
func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
||||
permissionType gtsmodel.DomainPermissionType,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
domain string,
|
||||
) (*apimodel.DomainPermission, string) {
|
||||
var (
|
||||
|
@ -154,7 +154,7 @@ func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
|||
|
||||
// To delete the permission,
|
||||
// first get it from the db.
|
||||
switch permissionType {
|
||||
switch permType {
|
||||
case gtsmodel.DomainPermissionBlock:
|
||||
domainPermission, _ = suite.db.GetDomainBlock(ctx, domain)
|
||||
case gtsmodel.DomainPermissionAllow:
|
||||
|
@ -170,7 +170,7 @@ func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
|||
// Now use the ID to delete it.
|
||||
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionDelete(
|
||||
ctx,
|
||||
permissionType,
|
||||
permType,
|
||||
suite.testAccounts["admin_account"],
|
||||
domainPermission.GetID(),
|
||||
)
|
||||
|
@ -246,7 +246,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndUnblockDomain() {
|
|||
actions: []domainPermAction{
|
||||
{
|
||||
createOrDelete: "create",
|
||||
permissionType: gtsmodel.DomainPermissionBlock,
|
||||
permType: gtsmodel.DomainPermissionBlock,
|
||||
domain: domain,
|
||||
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
||||
// Domain was blocked, so each
|
||||
|
@ -256,7 +256,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndUnblockDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "delete",
|
||||
permissionType: gtsmodel.DomainPermissionBlock,
|
||||
permType: gtsmodel.DomainPermissionBlock,
|
||||
domain: domain,
|
||||
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
||||
// Domain was unblocked, so each
|
||||
|
@ -279,7 +279,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
|||
actions: []domainPermAction{
|
||||
{
|
||||
createOrDelete: "create",
|
||||
permissionType: gtsmodel.DomainPermissionBlock,
|
||||
permType: gtsmodel.DomainPermissionBlock,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Domain was blocked, so each
|
||||
|
@ -316,7 +316,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "create",
|
||||
permissionType: gtsmodel.DomainPermissionAllow,
|
||||
permType: gtsmodel.DomainPermissionAllow,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Domain was explicitly allowed, so each
|
||||
|
@ -355,7 +355,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "delete",
|
||||
permissionType: gtsmodel.DomainPermissionAllow,
|
||||
permType: gtsmodel.DomainPermissionAllow,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Deleting the allow now, while there's
|
||||
|
@ -382,7 +382,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "delete",
|
||||
permissionType: gtsmodel.DomainPermissionBlock,
|
||||
permType: gtsmodel.DomainPermissionBlock,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Deleting the block now should
|
||||
|
@ -421,7 +421,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
|||
actions: []domainPermAction{
|
||||
{
|
||||
createOrDelete: "create",
|
||||
permissionType: gtsmodel.DomainPermissionAllow,
|
||||
permType: gtsmodel.DomainPermissionAllow,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Domain was explicitly allowed,
|
||||
|
@ -458,7 +458,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "create",
|
||||
permissionType: gtsmodel.DomainPermissionBlock,
|
||||
permType: gtsmodel.DomainPermissionBlock,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Create a block. An allow existed, so
|
||||
|
@ -497,7 +497,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
|||
},
|
||||
{
|
||||
createOrDelete: "delete",
|
||||
permissionType: gtsmodel.DomainPermissionAllow,
|
||||
permType: gtsmodel.DomainPermissionAllow,
|
||||
domain: domain,
|
||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||
// Deleting the allow now, while there's
|
||||
|
|
149
internal/processing/admin/domainpermissiondraft.go
Normal file
149
internal/processing/admin/domainpermissiondraft.go
Normal file
|
@ -0,0 +1,149 @@
|
|||
// 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 (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/paging"
|
||||
)
|
||||
|
||||
// DomainPermissionDraftGet returns one
|
||||
// domain permission draft with the given id.
|
||||
func (p *Processor) DomainPermissionDraftGet(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err = gtserror.Newf("db error getting domain permission draft %s: %w", id, err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
if permDraft == nil {
|
||||
err = fmt.Errorf("domain permission draft %s not found", id)
|
||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||
}
|
||||
|
||||
return p.apiDomainPerm(ctx, permDraft, false)
|
||||
}
|
||||
|
||||
// DomainPermissionDraftsGet returns a page of
|
||||
// DomainPermissionDrafts with the given parameters.
|
||||
func (p *Processor) DomainPermissionDraftsGet(
|
||||
ctx context.Context,
|
||||
subscriptionID string,
|
||||
domain string,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
page *paging.Page,
|
||||
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||
permDrafts, err := p.state.DB.GetDomainPermissionDrafts(
|
||||
ctx,
|
||||
permType,
|
||||
subscriptionID,
|
||||
domain,
|
||||
page,
|
||||
)
|
||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||
err := gtserror.Newf("db error: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
count := len(permDrafts)
|
||||
if count == 0 {
|
||||
return paging.EmptyResponse(), nil
|
||||
}
|
||||
|
||||
// Get the lowest and highest
|
||||
// ID values, used for paging.
|
||||
lo := permDrafts[count-1].ID
|
||||
hi := permDrafts[0].ID
|
||||
|
||||
// Convert each perm draft to API model.
|
||||
items := make([]any, len(permDrafts))
|
||||
for i, permDraft := range permDrafts {
|
||||
apiPermDraft, err := p.apiDomainPerm(ctx, permDraft, false)
|
||||
if err != nil {
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
items[i] = apiPermDraft
|
||||
}
|
||||
|
||||
// Assemble next/prev page queries.
|
||||
query := make(url.Values, 3)
|
||||
if subscriptionID != "" {
|
||||
query.Set(apiutil.DomainPermissionSubscriptionIDKey, subscriptionID)
|
||||
}
|
||||
if domain != "" {
|
||||
query.Set(apiutil.DomainPermissionDomainKey, domain)
|
||||
}
|
||||
if permType != gtsmodel.DomainPermissionUnknown {
|
||||
query.Set(apiutil.DomainPermissionPermTypeKey, permType.String())
|
||||
}
|
||||
|
||||
return paging.PackageResponse(paging.ResponseParams{
|
||||
Items: items,
|
||||
Path: "/api/v1/admin/domain_permission_drafts",
|
||||
Next: page.Next(lo, hi),
|
||||
Prev: page.Prev(lo, hi),
|
||||
Query: query,
|
||||
}), nil
|
||||
}
|
||||
|
||||
func (p *Processor) DomainPermissionDraftCreate(
|
||||
ctx context.Context,
|
||||
acct *gtsmodel.Account,
|
||||
domain string,
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
obfuscate bool,
|
||||
publicComment string,
|
||||
privateComment string,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
permDraft := >smodel.DomainPermissionDraft{
|
||||
ID: id.NewULID(),
|
||||
PermissionType: permType,
|
||||
Domain: domain,
|
||||
CreatedByAccountID: acct.ID,
|
||||
CreatedByAccount: acct,
|
||||
PrivateComment: privateComment,
|
||||
PublicComment: publicComment,
|
||||
Obfuscate: &obfuscate,
|
||||
}
|
||||
|
||||
if err := p.state.DB.PutDomainPermissionDraft(ctx, permDraft); err != nil {
|
||||
if errors.Is(err, db.ErrAlreadyExists) {
|
||||
const text = "a domain permission draft already exists with this permission type and domain"
|
||||
return nil, gtserror.NewErrorConflict(errors.New(text), text)
|
||||
}
|
||||
|
||||
// Real error.
|
||||
err := gtserror.Newf("db error putting domain permission draft: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return p.apiDomainPerm(ctx, permDraft, false)
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
"errors"
|
||||
"time"
|
||||
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
|
@ -97,3 +98,20 @@ func (p *Processor) rangeDomainAccounts(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// apiDomainPerm is a cheeky shortcut for returning
|
||||
// the API version of the given domain permission,
|
||||
// or an appropriate error if something goes wrong.
|
||||
func (p *Processor) apiDomainPerm(
|
||||
ctx context.Context,
|
||||
domainPermission gtsmodel.DomainPermission,
|
||||
export bool,
|
||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||
apiDomainPerm, err := p.converter.DomainPermToAPIDomainPerm(ctx, domainPermission, export)
|
||||
if err != nil {
|
||||
err := gtserror.NewfAt(3, "error converting domain permission to api model: %w", err)
|
||||
return nil, gtserror.NewErrorInternalError(err)
|
||||
}
|
||||
|
||||
return apiDomainPerm, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue