pee pee poo poo
This commit is contained in:
parent
5c818debb2
commit
9176b897da
|
@ -1130,6 +1130,78 @@ definitions:
|
|||
type: object
|
||||
x-go-name: DomainPermission
|
||||
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
|
||||
domainPermissionSubscription:
|
||||
properties:
|
||||
as_draft:
|
||||
description: 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
|
||||
type: boolean
|
||||
x-go-name: AsDraft
|
||||
content_type:
|
||||
description: MIME content type to use when parsing the permissions list.
|
||||
example: text/csv
|
||||
type: string
|
||||
x-go-name: ContentType
|
||||
count:
|
||||
description: Count of domain permission entries discovered at URI on last (successful) fetch.
|
||||
example: 53
|
||||
format: uint64
|
||||
readOnly: true
|
||||
type: integer
|
||||
x-go-name: Count
|
||||
created_by_account_id:
|
||||
description: ID of the account that created this subscription.
|
||||
example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||
readOnly: true
|
||||
type: string
|
||||
x-go-name: CreatedByAccountID
|
||||
error:
|
||||
description: 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
|
||||
type: string
|
||||
x-go-name: Error
|
||||
fetch_password:
|
||||
description: (Optional) password to set for basic auth when doing a fetch of URI.
|
||||
example: admin123
|
||||
type: string
|
||||
x-go-name: FetchPassword
|
||||
fetch_username:
|
||||
description: (Optional) username to set for basic auth when doing a fetch of URI.
|
||||
example: admin123
|
||||
type: string
|
||||
x-go-name: FetchUsername
|
||||
fetched_at:
|
||||
description: Time at which the most recent fetch was attempted (ISO 8601 Datetime).
|
||||
example: "2021-07-30T09:20:25+00:00"
|
||||
readOnly: true
|
||||
type: string
|
||||
x-go-name: FetchedAt
|
||||
id:
|
||||
description: The ID of the domain permission subscription.
|
||||
example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||
readOnly: true
|
||||
type: string
|
||||
x-go-name: ID
|
||||
permission_type:
|
||||
description: The type of domain permission subscription (allow, block).
|
||||
example: block
|
||||
type: string
|
||||
x-go-name: PermissionType
|
||||
title:
|
||||
description: Title of this list, as set by admin who created or updated it.f
|
||||
example: really cool list of neato pals
|
||||
type: string
|
||||
x-go-name: Title
|
||||
uri:
|
||||
description: URI to call in order to fetch the permissions list.
|
||||
example: https://www.example.org/blocklists/list1.csv
|
||||
type: string
|
||||
x-go-name: URI
|
||||
title: DomainPermissionSubscription represents an auto-refreshing subscription to a list of domain permissions (allows, blocks).
|
||||
type: object
|
||||
x-go-name: DomainPermissionSubscription
|
||||
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
|
||||
emoji:
|
||||
properties:
|
||||
category:
|
||||
|
@ -5997,6 +6069,70 @@ paths:
|
|||
summary: Get domain permission exclude with the given ID.
|
||||
tags:
|
||||
- admin
|
||||
/api/v1/admin/domain_permission_subscriptions:
|
||||
post:
|
||||
consumes:
|
||||
- multipart/form-data
|
||||
- application/json
|
||||
operationId: domainPermissionSubscriptionCreate
|
||||
parameters:
|
||||
- description: Optional title for this subscription.
|
||||
in: formData
|
||||
name: title
|
||||
type: string
|
||||
- description: Type of permissions to create by parsing the targeted file/list. One of "allow" or "block".
|
||||
in: formData
|
||||
name: permission_type
|
||||
required: true
|
||||
type: string
|
||||
- default: true
|
||||
description: 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. Defaults to "true".
|
||||
in: formData
|
||||
name: as_draft
|
||||
type: boolean
|
||||
- description: URI to call in order to fetch the permissions list.
|
||||
in: formData
|
||||
name: uri
|
||||
required: true
|
||||
type: string
|
||||
- description: MIME content type to use when parsing the permissions list. One of "text/plain", "text/csv", and "application/json".
|
||||
in: formData
|
||||
name: content_type
|
||||
required: true
|
||||
type: string
|
||||
- description: Optional basic auth username to provide when fetching given uri. If set, will be transmitted along with `fetch_password` when doing the fetch.
|
||||
in: formData
|
||||
name: fetch_username
|
||||
type: string
|
||||
- description: Optional basic auth password to provide when fetching given uri. If set, will be transmitted along with `fetch_username` when doing the fetch.
|
||||
in: formData
|
||||
name: fetch_password
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: The newly created domain permission subscription.
|
||||
schema:
|
||||
$ref: '#/definitions/domainPermissionSubscription'
|
||||
"400":
|
||||
description: bad request
|
||||
"401":
|
||||
description: unauthorized
|
||||
"403":
|
||||
description: forbidden
|
||||
"406":
|
||||
description: not acceptable
|
||||
"409":
|
||||
description: conflict
|
||||
"500":
|
||||
description: internal server error
|
||||
security:
|
||||
- OAuth2 Bearer:
|
||||
- admin
|
||||
summary: Create a domain permission subscription with the given parameters.
|
||||
tags:
|
||||
- admin
|
||||
/api/v1/admin/email/test:
|
||||
post:
|
||||
consumes:
|
||||
|
|
|
@ -28,43 +28,45 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
BasePath = "/v1/admin"
|
||||
EmojiPath = BasePath + "/custom_emojis"
|
||||
EmojiPathWithID = EmojiPath + "/:" + apiutil.IDKey
|
||||
EmojiCategoriesPath = EmojiPath + "/categories"
|
||||
DomainBlocksPath = BasePath + "/domain_blocks"
|
||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
||||
DomainAllowsPath = BasePath + "/domain_allows"
|
||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftsPath = BasePath + "/domain_permission_drafts"
|
||||
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
||||
DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
|
||||
DomainPermissionExcludesPath = BasePath + "/domain_permission_excludes"
|
||||
DomainPermissionExcludesPathWithID = DomainPermissionExcludesPath + "/:" + apiutil.IDKey
|
||||
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
||||
HeaderAllowsPath = BasePath + "/header_allows"
|
||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
||||
HeaderBlocksPath = BasePath + "/header_blocks"
|
||||
HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + apiutil.IDKey
|
||||
AccountsV1Path = BasePath + "/accounts"
|
||||
AccountsV2Path = "/v2/admin/accounts"
|
||||
AccountsPathWithID = AccountsV1Path + "/:" + apiutil.IDKey
|
||||
AccountsActionPath = AccountsPathWithID + "/action"
|
||||
AccountsApprovePath = AccountsPathWithID + "/approve"
|
||||
AccountsRejectPath = AccountsPathWithID + "/reject"
|
||||
MediaCleanupPath = BasePath + "/media_cleanup"
|
||||
MediaRefetchPath = BasePath + "/media_refetch"
|
||||
ReportsPath = BasePath + "/reports"
|
||||
ReportsPathWithID = ReportsPath + "/:" + apiutil.IDKey
|
||||
ReportsResolvePath = ReportsPathWithID + "/resolve"
|
||||
EmailPath = BasePath + "/email"
|
||||
EmailTestPath = EmailPath + "/test"
|
||||
InstanceRulesPath = BasePath + "/instance/rules"
|
||||
InstanceRulesPathWithID = InstanceRulesPath + "/:" + apiutil.IDKey
|
||||
DebugPath = BasePath + "/debug"
|
||||
DebugAPUrlPath = DebugPath + "/apurl"
|
||||
DebugClearCachesPath = DebugPath + "/caches/clear"
|
||||
BasePath = "/v1/admin"
|
||||
EmojiPath = BasePath + "/custom_emojis"
|
||||
EmojiPathWithID = EmojiPath + "/:" + apiutil.IDKey
|
||||
EmojiCategoriesPath = EmojiPath + "/categories"
|
||||
DomainBlocksPath = BasePath + "/domain_blocks"
|
||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
||||
DomainAllowsPath = BasePath + "/domain_allows"
|
||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftsPath = BasePath + "/domain_permission_drafts"
|
||||
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
||||
DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
|
||||
DomainPermissionExcludesPath = BasePath + "/domain_permission_excludes"
|
||||
DomainPermissionExcludesPathWithID = DomainPermissionExcludesPath + "/:" + apiutil.IDKey
|
||||
DomainPermissionSubscriptionsPath = BasePath + "/domain_permission_subscriptions"
|
||||
DomainPermissionSubscriptionsPathWithID = DomainPermissionSubscriptionsPath + "/:" + apiutil.IDKey
|
||||
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
||||
HeaderAllowsPath = BasePath + "/header_allows"
|
||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
||||
HeaderBlocksPath = BasePath + "/header_blocks"
|
||||
HeaderBlocksPathWithID = HeaderBlocksPath + "/:" + apiutil.IDKey
|
||||
AccountsV1Path = BasePath + "/accounts"
|
||||
AccountsV2Path = "/v2/admin/accounts"
|
||||
AccountsPathWithID = AccountsV1Path + "/:" + apiutil.IDKey
|
||||
AccountsActionPath = AccountsPathWithID + "/action"
|
||||
AccountsApprovePath = AccountsPathWithID + "/approve"
|
||||
AccountsRejectPath = AccountsPathWithID + "/reject"
|
||||
MediaCleanupPath = BasePath + "/media_cleanup"
|
||||
MediaRefetchPath = BasePath + "/media_refetch"
|
||||
ReportsPath = BasePath + "/reports"
|
||||
ReportsPathWithID = ReportsPath + "/:" + apiutil.IDKey
|
||||
ReportsResolvePath = ReportsPathWithID + "/resolve"
|
||||
EmailPath = BasePath + "/email"
|
||||
EmailTestPath = EmailPath + "/test"
|
||||
InstanceRulesPath = BasePath + "/instance/rules"
|
||||
InstanceRulesPathWithID = InstanceRulesPath + "/:" + apiutil.IDKey
|
||||
DebugPath = BasePath + "/debug"
|
||||
DebugAPUrlPath = DebugPath + "/apurl"
|
||||
DebugClearCachesPath = DebugPath + "/caches/clear"
|
||||
|
||||
FilterQueryKey = "filter"
|
||||
MaxShortcodeDomainKey = "max_shortcode_domain"
|
||||
|
@ -118,6 +120,9 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
|||
attachHandler(http.MethodGet, DomainPermissionExcludesPathWithID, m.DomainPermissionExcludeGETHandler)
|
||||
attachHandler(http.MethodDelete, DomainPermissionExcludesPathWithID, m.DomainPermissionExcludeDELETEHandler)
|
||||
|
||||
// domain permission subscriptions stuff
|
||||
attachHandler(http.MethodPost, DomainPermissionSubscriptionsPath, m.DomainPermissionSubscriptionPOSTHandler)
|
||||
|
||||
// header filtering administration routes
|
||||
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
|
||||
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
|
||||
|
|
|
@ -302,3 +302,41 @@ func (m *Module) getDomainPermissions(
|
|||
|
||||
apiutil.JSON(c, http.StatusOK, domainPerm)
|
||||
}
|
||||
|
||||
func parseDomainPermissionType(permTypeStr string) (
|
||||
permType gtsmodel.DomainPermissionType,
|
||||
errWithCode gtserror.WithCode,
|
||||
) {
|
||||
if permTypeStr == "" {
|
||||
const errText = "permission_type not set, must be one of block or allow"
|
||||
errWithCode = gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
return
|
||||
}
|
||||
|
||||
permType = gtsmodel.NewDomainPermissionType(permTypeStr)
|
||||
if permType == gtsmodel.DomainPermissionUnknown {
|
||||
var errText = fmt.Sprintf("permission_type %s not recognized, must be one of block or allow", permTypeStr)
|
||||
errWithCode = gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func parseDomainPermSubContentType(contentTypeStr string) (
|
||||
contentType gtsmodel.DomainPermSubContentType,
|
||||
errWithCode gtserror.WithCode,
|
||||
) {
|
||||
if contentTypeStr == "" {
|
||||
const errText = "content_type not set, must be one of text/csv, text/plain or application/json"
|
||||
errWithCode = gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
return
|
||||
}
|
||||
|
||||
contentType = gtsmodel.NewDomainPermSubContentType(contentTypeStr)
|
||||
if contentType == gtsmodel.DomainPermSubContentTypeUnknown {
|
||||
var errText = fmt.Sprintf("content_type %s not recognized, must be one of text/csv, text/plain or application/json", contentTypeStr)
|
||||
errWithCode = gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
// GoToSocial
|
||||
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||
)
|
||||
|
||||
// DomainPermissionSubscriptionPOSTHandler swagger:operation POST /api/v1/admin/domain_permission_subscriptions domainPermissionSubscriptionCreate
|
||||
//
|
||||
// Create a domain permission subscription with the given parameters.
|
||||
//
|
||||
// ---
|
||||
// tags:
|
||||
// - admin
|
||||
//
|
||||
// consumes:
|
||||
// - multipart/form-data
|
||||
// - application/json
|
||||
//
|
||||
// produces:
|
||||
// - application/json
|
||||
//
|
||||
// parameters:
|
||||
// -
|
||||
// name: title
|
||||
// in: formData
|
||||
// description: Optional title for this subscription.
|
||||
// type: string
|
||||
// -
|
||||
// name: permission_type
|
||||
// required: true
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Type of permissions to create by parsing the targeted file/list.
|
||||
// One of "allow" or "block".
|
||||
// type: string
|
||||
// -
|
||||
// name: as_draft
|
||||
// in: formData
|
||||
// description: >-
|
||||
// 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.
|
||||
// Defaults to "true".
|
||||
// type: boolean
|
||||
// default: true
|
||||
// -
|
||||
// name: uri
|
||||
// required: true
|
||||
// in: formData
|
||||
// description: URI to call in order to fetch the permissions list.
|
||||
// type: string
|
||||
// -
|
||||
// name: content_type
|
||||
// required: true
|
||||
// in: formData
|
||||
// description: >-
|
||||
// MIME content type to use when parsing the permissions list.
|
||||
// One of "text/plain", "text/csv", and "application/json".
|
||||
// type: string
|
||||
// -
|
||||
// name: fetch_username
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Optional basic auth username to provide when fetching given uri.
|
||||
// If set, will be transmitted along with `fetch_password` when doing the fetch.
|
||||
// type: string
|
||||
// -
|
||||
// name: fetch_password
|
||||
// in: formData
|
||||
// description: >-
|
||||
// Optional basic auth password to provide when fetching given uri.
|
||||
// If set, will be transmitted along with `fetch_username` when doing the fetch.
|
||||
// type: string
|
||||
//
|
||||
// security:
|
||||
// - OAuth2 Bearer:
|
||||
// - admin
|
||||
//
|
||||
// responses:
|
||||
// '200':
|
||||
// description: The newly created domain permission subscription.
|
||||
// schema:
|
||||
// "$ref": "#/definitions/domainPermissionSubscription"
|
||||
// '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) DomainPermissionSubscriptionPOSTHandler(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.DomainPermissionSubscriptionRequest)
|
||||
if err := c.ShouldBind(form); err != nil {
|
||||
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
if form.URI == "" {
|
||||
const errText = "uri must be set"
|
||||
errWithCode := gtserror.NewErrorBadRequest(errors.New(errText), errText)
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
permType, errWithCode := parseDomainPermissionType(form.PermissionType)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
contentType, errWithCode := parseDomainPermSubContentType(form.ContentType)
|
||||
if errWithCode != nil {
|
||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||
return
|
||||
}
|
||||
|
||||
permDraft, errWithCode := m.processor.Admin().DomainPermissionSubscriptionCreate(
|
||||
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)
|
||||
}
|
|
@ -99,3 +99,77 @@ type DomainKeysExpireRequest struct {
|
|||
// hostname/domain to expire keys for.
|
||||
Domain string `form:"domain" json:"domain"`
|
||||
}
|
||||
|
||||
// DomainPermissionSubscription represents an auto-refreshing subscription to a list of domain permissions (allows, blocks).
|
||||
//
|
||||
// swagger:model domainPermissionSubscription
|
||||
type DomainPermissionSubscription struct {
|
||||
// The ID of the domain permission subscription.
|
||||
// example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||
// readonly: true
|
||||
ID string `json:"id"`
|
||||
// Title of this list, as set by admin who created or updated it.f
|
||||
// example: really cool list of neato pals
|
||||
Title string `json:"title"`
|
||||
// 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"`
|
||||
// URI to call in order to fetch the permissions list.
|
||||
// example: https://www.example.org/blocklists/list1.csv
|
||||
URI string `json:"uri"`
|
||||
// MIME content type to use when parsing the permissions list.
|
||||
// example: text/csv
|
||||
ContentType string `json:"content_type"`
|
||||
// (Optional) username to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchUsername string `json:"fetch_username,omitempty"`
|
||||
// (Optional) password to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchPassword string `json:"fetch_password,omitempty"`
|
||||
// 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,omitempty"`
|
||||
// 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,omitempty"`
|
||||
// Count of domain permission entries discovered at URI on last (successful) fetch.
|
||||
// example: 53
|
||||
// readonly: true
|
||||
Count uint64 `json:"count"`
|
||||
}
|
||||
|
||||
// DomainPermissionSubscriptionRequest represents a request to create or update a domain permission subscription..
|
||||
//
|
||||
// swagger:ignore
|
||||
type DomainPermissionSubscriptionRequest struct {
|
||||
// Title of this subscription, as set by admin who created or updated it.
|
||||
// example: really cool list of neato pals
|
||||
Title string `form:"title" json:"title"`
|
||||
// The type of domain permission subscription (allow, block).
|
||||
// example: block
|
||||
PermissionType string `form:"permission_type" 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 `form:"as_draft" json:"as_draft"`
|
||||
// URI to call in order to fetch the permissions list.
|
||||
// example: https://www.example.org/blocklists/list1.csv
|
||||
URI string `form:"uri" json:"uri"`
|
||||
// MIME content type to use when parsing the permissions list.
|
||||
// example: text/csv
|
||||
ContentType string `form:"content_type" json:"content_type"`
|
||||
// (Optional) username to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchUsername string `form:"fetch_username" json:"fetch_username"`
|
||||
// (Optional) password to set for basic auth when doing a fetch of URI.
|
||||
// example: admin123
|
||||
FetchPassword string `form:"fetch_password" json:"fetch_password"`
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ func (c *Caches) Init() {
|
|||
c.initDomainAllow()
|
||||
c.initDomainBlock()
|
||||
c.initDomainPermissionDraft()
|
||||
c.initDomainPermissionSubscription()
|
||||
c.initDomainPermissionExclude()
|
||||
c.initEmoji()
|
||||
c.initEmojiCategory()
|
||||
|
|
|
@ -70,6 +70,9 @@ type DBCaches struct {
|
|||
// 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]
|
||||
|
||||
// DomainPermissionExclude provides access to the domain permission exclude database cache.
|
||||
DomainPermissionExclude *domain.Cache
|
||||
|
||||
|
@ -586,6 +589,37 @@ func (c *Caches) initDomainPermissionDraft() {
|
|||
})
|
||||
}
|
||||
|
||||
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) initDomainPermissionExclude() {
|
||||
c.DB.DomainPermissionExclude = new(domain.Cache)
|
||||
}
|
||||
|
|
|
@ -357,6 +357,20 @@ func sizeofDomainPermissionDraft() uintptr {
|
|||
}))
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -196,59 +196,60 @@ type HTTPClientConfiguration struct {
|
|||
}
|
||||
|
||||
type CacheConfiguration struct {
|
||||
MemoryTarget bytesize.Size `name:"memory-target"`
|
||||
AccountMemRatio float64 `name:"account-mem-ratio"`
|
||||
AccountNoteMemRatio float64 `name:"account-note-mem-ratio"`
|
||||
AccountSettingsMemRatio float64 `name:"account-settings-mem-ratio"`
|
||||
AccountStatsMemRatio float64 `name:"account-stats-mem-ratio"`
|
||||
ApplicationMemRatio float64 `name:"application-mem-ratio"`
|
||||
BlockMemRatio float64 `name:"block-mem-ratio"`
|
||||
BlockIDsMemRatio float64 `name:"block-ids-mem-ratio"`
|
||||
BoostOfIDsMemRatio float64 `name:"boost-of-ids-mem-ratio"`
|
||||
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"`
|
||||
EmojiMemRatio float64 `name:"emoji-mem-ratio"`
|
||||
EmojiCategoryMemRatio float64 `name:"emoji-category-mem-ratio"`
|
||||
FilterMemRatio float64 `name:"filter-mem-ratio"`
|
||||
FilterKeywordMemRatio float64 `name:"filter-keyword-mem-ratio"`
|
||||
FilterStatusMemRatio float64 `name:"filter-status-mem-ratio"`
|
||||
FollowMemRatio float64 `name:"follow-mem-ratio"`
|
||||
FollowIDsMemRatio float64 `name:"follow-ids-mem-ratio"`
|
||||
FollowRequestMemRatio float64 `name:"follow-request-mem-ratio"`
|
||||
FollowRequestIDsMemRatio float64 `name:"follow-request-ids-mem-ratio"`
|
||||
FollowingTagIDsMemRatio float64 `name:"following-tag-ids-mem-ratio"`
|
||||
InReplyToIDsMemRatio float64 `name:"in-reply-to-ids-mem-ratio"`
|
||||
InstanceMemRatio float64 `name:"instance-mem-ratio"`
|
||||
InteractionRequestMemRatio float64 `name:"interaction-request-mem-ratio"`
|
||||
ListMemRatio float64 `name:"list-mem-ratio"`
|
||||
ListIDsMemRatio float64 `name:"list-ids-mem-ratio"`
|
||||
ListedIDsMemRatio float64 `name:"listed-ids-mem-ratio"`
|
||||
MarkerMemRatio float64 `name:"marker-mem-ratio"`
|
||||
MediaMemRatio float64 `name:"media-mem-ratio"`
|
||||
MentionMemRatio float64 `name:"mention-mem-ratio"`
|
||||
MoveMemRatio float64 `name:"move-mem-ratio"`
|
||||
NotificationMemRatio float64 `name:"notification-mem-ratio"`
|
||||
PollMemRatio float64 `name:"poll-mem-ratio"`
|
||||
PollVoteMemRatio float64 `name:"poll-vote-mem-ratio"`
|
||||
PollVoteIDsMemRatio float64 `name:"poll-vote-ids-mem-ratio"`
|
||||
ReportMemRatio float64 `name:"report-mem-ratio"`
|
||||
SinBinStatusMemRatio float64 `name:"sin-bin-status-mem-ratio"`
|
||||
StatusMemRatio float64 `name:"status-mem-ratio"`
|
||||
StatusBookmarkMemRatio float64 `name:"status-bookmark-mem-ratio"`
|
||||
StatusBookmarkIDsMemRatio float64 `name:"status-bookmark-ids-mem-ratio"`
|
||||
StatusFaveMemRatio float64 `name:"status-fave-mem-ratio"`
|
||||
StatusFaveIDsMemRatio float64 `name:"status-fave-ids-mem-ratio"`
|
||||
TagMemRatio float64 `name:"tag-mem-ratio"`
|
||||
ThreadMuteMemRatio float64 `name:"thread-mute-mem-ratio"`
|
||||
TokenMemRatio float64 `name:"token-mem-ratio"`
|
||||
TombstoneMemRatio float64 `name:"tombstone-mem-ratio"`
|
||||
UserMemRatio float64 `name:"user-mem-ratio"`
|
||||
UserMuteMemRatio float64 `name:"user-mute-mem-ratio"`
|
||||
UserMuteIDsMemRatio float64 `name:"user-mute-ids-mem-ratio"`
|
||||
WebfingerMemRatio float64 `name:"webfinger-mem-ratio"`
|
||||
VisibilityMemRatio float64 `name:"visibility-mem-ratio"`
|
||||
MemoryTarget bytesize.Size `name:"memory-target"`
|
||||
AccountMemRatio float64 `name:"account-mem-ratio"`
|
||||
AccountNoteMemRatio float64 `name:"account-note-mem-ratio"`
|
||||
AccountSettingsMemRatio float64 `name:"account-settings-mem-ratio"`
|
||||
AccountStatsMemRatio float64 `name:"account-stats-mem-ratio"`
|
||||
ApplicationMemRatio float64 `name:"application-mem-ratio"`
|
||||
BlockMemRatio float64 `name:"block-mem-ratio"`
|
||||
BlockIDsMemRatio float64 `name:"block-ids-mem-ratio"`
|
||||
BoostOfIDsMemRatio float64 `name:"boost-of-ids-mem-ratio"`
|
||||
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"`
|
||||
FilterKeywordMemRatio float64 `name:"filter-keyword-mem-ratio"`
|
||||
FilterStatusMemRatio float64 `name:"filter-status-mem-ratio"`
|
||||
FollowMemRatio float64 `name:"follow-mem-ratio"`
|
||||
FollowIDsMemRatio float64 `name:"follow-ids-mem-ratio"`
|
||||
FollowRequestMemRatio float64 `name:"follow-request-mem-ratio"`
|
||||
FollowRequestIDsMemRatio float64 `name:"follow-request-ids-mem-ratio"`
|
||||
FollowingTagIDsMemRatio float64 `name:"following-tag-ids-mem-ratio"`
|
||||
InReplyToIDsMemRatio float64 `name:"in-reply-to-ids-mem-ratio"`
|
||||
InstanceMemRatio float64 `name:"instance-mem-ratio"`
|
||||
InteractionRequestMemRatio float64 `name:"interaction-request-mem-ratio"`
|
||||
ListMemRatio float64 `name:"list-mem-ratio"`
|
||||
ListIDsMemRatio float64 `name:"list-ids-mem-ratio"`
|
||||
ListedIDsMemRatio float64 `name:"listed-ids-mem-ratio"`
|
||||
MarkerMemRatio float64 `name:"marker-mem-ratio"`
|
||||
MediaMemRatio float64 `name:"media-mem-ratio"`
|
||||
MentionMemRatio float64 `name:"mention-mem-ratio"`
|
||||
MoveMemRatio float64 `name:"move-mem-ratio"`
|
||||
NotificationMemRatio float64 `name:"notification-mem-ratio"`
|
||||
PollMemRatio float64 `name:"poll-mem-ratio"`
|
||||
PollVoteMemRatio float64 `name:"poll-vote-mem-ratio"`
|
||||
PollVoteIDsMemRatio float64 `name:"poll-vote-ids-mem-ratio"`
|
||||
ReportMemRatio float64 `name:"report-mem-ratio"`
|
||||
SinBinStatusMemRatio float64 `name:"sin-bin-status-mem-ratio"`
|
||||
StatusMemRatio float64 `name:"status-mem-ratio"`
|
||||
StatusBookmarkMemRatio float64 `name:"status-bookmark-mem-ratio"`
|
||||
StatusBookmarkIDsMemRatio float64 `name:"status-bookmark-ids-mem-ratio"`
|
||||
StatusFaveMemRatio float64 `name:"status-fave-mem-ratio"`
|
||||
StatusFaveIDsMemRatio float64 `name:"status-fave-ids-mem-ratio"`
|
||||
TagMemRatio float64 `name:"tag-mem-ratio"`
|
||||
ThreadMuteMemRatio float64 `name:"thread-mute-mem-ratio"`
|
||||
TokenMemRatio float64 `name:"token-mem-ratio"`
|
||||
TombstoneMemRatio float64 `name:"tombstone-mem-ratio"`
|
||||
UserMemRatio float64 `name:"user-mem-ratio"`
|
||||
UserMuteMemRatio float64 `name:"user-mute-mem-ratio"`
|
||||
UserMuteIDsMemRatio float64 `name:"user-mute-ids-mem-ratio"`
|
||||
WebfingerMemRatio float64 `name:"webfinger-mem-ratio"`
|
||||
VisibilityMemRatio float64 `name:"visibility-mem-ratio"`
|
||||
}
|
||||
|
||||
// MarshalMap will marshal current Configuration into a map structure (useful for JSON/TOML/YAML).
|
||||
|
|
|
@ -158,58 +158,59 @@ var Defaults = Configuration{
|
|||
// when TODO items in the size.go source
|
||||
// file have been addressed, these should
|
||||
// be able to make some more sense :D
|
||||
AccountMemRatio: 5,
|
||||
AccountNoteMemRatio: 1,
|
||||
AccountSettingsMemRatio: 0.1,
|
||||
AccountStatsMemRatio: 2,
|
||||
ApplicationMemRatio: 0.1,
|
||||
BlockMemRatio: 2,
|
||||
BlockIDsMemRatio: 3,
|
||||
BoostOfIDsMemRatio: 3,
|
||||
ClientMemRatio: 0.1,
|
||||
ConversationMemRatio: 1,
|
||||
ConversationLastStatusIDsMemRatio: 2,
|
||||
DomainPermissionDraftMemRation: 0.5,
|
||||
EmojiMemRatio: 3,
|
||||
EmojiCategoryMemRatio: 0.1,
|
||||
FilterMemRatio: 0.5,
|
||||
FilterKeywordMemRatio: 0.5,
|
||||
FilterStatusMemRatio: 0.5,
|
||||
FollowMemRatio: 2,
|
||||
FollowIDsMemRatio: 4,
|
||||
FollowRequestMemRatio: 2,
|
||||
FollowRequestIDsMemRatio: 2,
|
||||
FollowingTagIDsMemRatio: 2,
|
||||
InReplyToIDsMemRatio: 3,
|
||||
InstanceMemRatio: 1,
|
||||
InteractionRequestMemRatio: 1,
|
||||
ListMemRatio: 1,
|
||||
ListIDsMemRatio: 2,
|
||||
ListedIDsMemRatio: 2,
|
||||
MarkerMemRatio: 0.5,
|
||||
MediaMemRatio: 4,
|
||||
MentionMemRatio: 2,
|
||||
MoveMemRatio: 0.1,
|
||||
NotificationMemRatio: 2,
|
||||
PollMemRatio: 1,
|
||||
PollVoteMemRatio: 2,
|
||||
PollVoteIDsMemRatio: 2,
|
||||
ReportMemRatio: 1,
|
||||
SinBinStatusMemRatio: 0.5,
|
||||
StatusMemRatio: 5,
|
||||
StatusBookmarkMemRatio: 0.5,
|
||||
StatusBookmarkIDsMemRatio: 2,
|
||||
StatusFaveMemRatio: 2,
|
||||
StatusFaveIDsMemRatio: 3,
|
||||
TagMemRatio: 2,
|
||||
ThreadMuteMemRatio: 0.2,
|
||||
TokenMemRatio: 0.75,
|
||||
TombstoneMemRatio: 0.5,
|
||||
UserMemRatio: 0.25,
|
||||
UserMuteMemRatio: 2,
|
||||
UserMuteIDsMemRatio: 3,
|
||||
WebfingerMemRatio: 0.1,
|
||||
VisibilityMemRatio: 2,
|
||||
AccountMemRatio: 5,
|
||||
AccountNoteMemRatio: 1,
|
||||
AccountSettingsMemRatio: 0.1,
|
||||
AccountStatsMemRatio: 2,
|
||||
ApplicationMemRatio: 0.1,
|
||||
BlockMemRatio: 2,
|
||||
BlockIDsMemRatio: 3,
|
||||
BoostOfIDsMemRatio: 3,
|
||||
ClientMemRatio: 0.1,
|
||||
ConversationMemRatio: 1,
|
||||
ConversationLastStatusIDsMemRatio: 2,
|
||||
DomainPermissionDraftMemRation: 0.5,
|
||||
DomainPermissionSubscriptionMemRation: 0.5,
|
||||
EmojiMemRatio: 3,
|
||||
EmojiCategoryMemRatio: 0.1,
|
||||
FilterMemRatio: 0.5,
|
||||
FilterKeywordMemRatio: 0.5,
|
||||
FilterStatusMemRatio: 0.5,
|
||||
FollowMemRatio: 2,
|
||||
FollowIDsMemRatio: 4,
|
||||
FollowRequestMemRatio: 2,
|
||||
FollowRequestIDsMemRatio: 2,
|
||||
FollowingTagIDsMemRatio: 2,
|
||||
InReplyToIDsMemRatio: 3,
|
||||
InstanceMemRatio: 1,
|
||||
InteractionRequestMemRatio: 1,
|
||||
ListMemRatio: 1,
|
||||
ListIDsMemRatio: 2,
|
||||
ListedIDsMemRatio: 2,
|
||||
MarkerMemRatio: 0.5,
|
||||
MediaMemRatio: 4,
|
||||
MentionMemRatio: 2,
|
||||
MoveMemRatio: 0.1,
|
||||
NotificationMemRatio: 2,
|
||||
PollMemRatio: 1,
|
||||
PollVoteMemRatio: 2,
|
||||
PollVoteIDsMemRatio: 2,
|
||||
ReportMemRatio: 1,
|
||||
SinBinStatusMemRatio: 0.5,
|
||||
StatusMemRatio: 5,
|
||||
StatusBookmarkMemRatio: 0.5,
|
||||
StatusBookmarkIDsMemRatio: 2,
|
||||
StatusFaveMemRatio: 2,
|
||||
StatusFaveIDsMemRatio: 3,
|
||||
TagMemRatio: 2,
|
||||
ThreadMuteMemRatio: 0.2,
|
||||
TokenMemRatio: 0.75,
|
||||
TombstoneMemRatio: 0.5,
|
||||
UserMemRatio: 0.25,
|
||||
UserMuteMemRatio: 2,
|
||||
UserMuteIDsMemRatio: 3,
|
||||
WebfingerMemRatio: 0.1,
|
||||
VisibilityMemRatio: 2,
|
||||
},
|
||||
|
||||
HTTPClient: HTTPClientConfiguration{
|
||||
|
|
|
@ -3187,6 +3187,37 @@ 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()
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
// 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 bundb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"slices"
|
||||
|
||||
"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/uptrace/bun"
|
||||
)
|
||||
|
||||
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 permission type.
|
||||
if permType != gtsmodel.DomainPermissionUnknown {
|
||||
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
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// 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_subscriptions`.
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model((*gtsmodel.DomainPermissionSubscription)(nil)).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes. Indices. Indie sexes.
|
||||
for table, indexes := range map[string]map[string][]string{
|
||||
"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)
|
||||
}
|
||||
}
|
|
@ -132,4 +132,25 @@ type Domain interface {
|
|||
|
||||
// IsDomainPermissionExcluded returns true if the given domain matches in the list of excluded domains.
|
||||
IsDomainPermissionExcluded(ctx context.Context, domain string) (bool, 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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// 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:",nullzero,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.
|
||||
URI string `bun:",unique,nullzero,notnull"` // URI of the domain permission list.
|
||||
ContentType DomainPermSubContentType `bun:",nullzero,notnull"` // Content type to expect from the URI.
|
||||
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.
|
||||
SuccessfullyFetchedAt time.Time `bun:"type:timestamptz,nullzero"` // Time when the domain permission list was last *successfuly* fetched, to be transmitted as If-Modified-Since header.
|
||||
ETag string `bun:",nullzero"` // Etag last received from the server (if any) on successful fetch.
|
||||
Error string `bun:",nullzero"` // If latest fetch attempt errored, this field stores the error message. Cleared on latest successful fetch.
|
||||
Count uint64 `bun:""` // Count of domain permission entries discovered at URI.
|
||||
}
|
||||
|
||||
type DomainPermSubContentType uint8
|
||||
|
||||
const (
|
||||
DomainPermSubContentTypeUnknown DomainPermSubContentType = iota
|
||||
DomainPermSubContentTypeCSV // text/csv
|
||||
DomainPermSubContentTypeJSON // application/json
|
||||
DomainPermSubContentTypePlain // text/plain
|
||||
)
|
||||
|
||||
func (p DomainPermSubContentType) String() string {
|
||||
switch p {
|
||||
case DomainPermSubContentTypeCSV:
|
||||
return "text/csv"
|
||||
case DomainPermSubContentTypeJSON:
|
||||
return "application/json"
|
||||
case DomainPermSubContentTypePlain:
|
||||
return "text/plain"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func NewDomainPermSubContentType(in string) DomainPermSubContentType {
|
||||
switch in {
|
||||
case "text/csv":
|
||||
return DomainPermSubContentTypeCSV
|
||||
case "application/json":
|
||||
return DomainPermSubContentTypeCSV
|
||||
case "text/plain":
|
||||
return DomainPermSubContentTypeCSV
|
||||
default:
|
||||
return DomainPermSubContentTypeUnknown
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// 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"
|
||||
|
||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
||||
)
|
||||
|
||||
func (p *Processor) DomainPermissionSubscriptionCreate(
|
||||
ctx context.Context,
|
||||
acct *gtsmodel.Account,
|
||||
) {
|
||||
|
||||
}
|
Loading…
Reference in New Issue