mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-22 11:46:40 +00:00
Compare commits
2 commits
97187464c4
...
5aa520a17c
Author | SHA1 | Date | |
---|---|---|---|
5aa520a17c | |||
c8647f701c |
|
@ -1124,6 +1124,73 @@ definitions:
|
||||||
type: object
|
type: object
|
||||||
x-go-name: DomainPermission
|
x-go-name: DomainPermission
|
||||||
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
|
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 expect at URI.
|
||||||
|
example: text/csv
|
||||||
|
type: string
|
||||||
|
x-go-name: ContentType
|
||||||
|
count:
|
||||||
|
description: Count of domain permission entries discovered at URI.
|
||||||
|
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
|
||||||
|
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:
|
emoji:
|
||||||
properties:
|
properties:
|
||||||
category:
|
category:
|
||||||
|
@ -5572,6 +5639,249 @@ paths:
|
||||||
summary: Force expiry of cached public keys for all accounts on the given domain stored in your database.
|
summary: Force expiry of cached public keys for all accounts on the given domain stored in your database.
|
||||||
tags:
|
tags:
|
||||||
- admin
|
- admin
|
||||||
|
/api/v1/admin/domain_permission_drafts:
|
||||||
|
get:
|
||||||
|
description: |-
|
||||||
|
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"
|
||||||
|
````
|
||||||
|
operationId: domainPermissionDraftsGet
|
||||||
|
parameters:
|
||||||
|
- description: Show only drafts created by the given subscription ID.
|
||||||
|
in: query
|
||||||
|
name: subscription_id
|
||||||
|
type: string
|
||||||
|
- description: Return only drafts that target the given domain.
|
||||||
|
in: query
|
||||||
|
name: domain
|
||||||
|
type: string
|
||||||
|
- description: Filter on "block" or "allow" type drafts.
|
||||||
|
in: query
|
||||||
|
name: permission_type
|
||||||
|
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: max_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: since_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: min_id
|
||||||
|
type: string
|
||||||
|
- default: 20
|
||||||
|
description: Number of items to return.
|
||||||
|
in: query
|
||||||
|
maximum: 100
|
||||||
|
minimum: 1
|
||||||
|
name: limit
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Domain permission drafts.
|
||||||
|
headers:
|
||||||
|
Link:
|
||||||
|
description: Links to the next and previous queries.
|
||||||
|
type: string
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/domainPermission'
|
||||||
|
type: array
|
||||||
|
"400":
|
||||||
|
description: bad request
|
||||||
|
"401":
|
||||||
|
description: unauthorized
|
||||||
|
"403":
|
||||||
|
description: forbidden
|
||||||
|
"404":
|
||||||
|
description: not found
|
||||||
|
"406":
|
||||||
|
description: not acceptable
|
||||||
|
"500":
|
||||||
|
description: internal server error
|
||||||
|
security:
|
||||||
|
- OAuth2 Bearer:
|
||||||
|
- admin
|
||||||
|
summary: View domain permission drafts.
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
- application/json
|
||||||
|
operationId: domainPermissionDraftCreate
|
||||||
|
parameters:
|
||||||
|
- description: Domain to create the permission draft for.
|
||||||
|
in: formData
|
||||||
|
name: domain
|
||||||
|
type: string
|
||||||
|
- description: Create a draft "allow" or a draft "block".
|
||||||
|
in: query
|
||||||
|
name: permission_type
|
||||||
|
type: string
|
||||||
|
- description: Obfuscate the name of the domain when serving it publicly. Eg., `example.org` becomes something like `ex***e.org`.
|
||||||
|
in: formData
|
||||||
|
name: obfuscate
|
||||||
|
type: boolean
|
||||||
|
- description: Public comment about this domain permission. This will be displayed alongside the domain permission if you choose to share permissions.
|
||||||
|
in: formData
|
||||||
|
name: public_comment
|
||||||
|
type: string
|
||||||
|
- 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.
|
||||||
|
in: formData
|
||||||
|
name: private_comment
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The newly created domain permission draft.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domainPermission'
|
||||||
|
"400":
|
||||||
|
description: bad request
|
||||||
|
"401":
|
||||||
|
description: unauthorized
|
||||||
|
"403":
|
||||||
|
description: forbidden
|
||||||
|
"406":
|
||||||
|
description: not acceptable
|
||||||
|
"409":
|
||||||
|
description: conflict
|
||||||
|
"500":
|
||||||
|
description: internal server error
|
||||||
|
security:
|
||||||
|
- OAuth2 Bearer:
|
||||||
|
- admin
|
||||||
|
summary: Create a domain permission draft with the given parameters.
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
|
/api/v1/admin/domain_permission_drafts/{id}:
|
||||||
|
get:
|
||||||
|
operationId: domainPermissionDraftGet
|
||||||
|
parameters:
|
||||||
|
- description: ID of the domain permission draft.
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
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
|
||||||
|
security:
|
||||||
|
- OAuth2 Bearer:
|
||||||
|
- admin
|
||||||
|
summary: Get domain permission draft with the given ID.
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
|
/api/v1/admin/domain_permission_drafts/{id}/accept:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
- application/json
|
||||||
|
operationId: domainPermissionDraftAccept
|
||||||
|
parameters:
|
||||||
|
- description: ID of the domain permission draft.
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: false
|
||||||
|
description: If a domain permission already exists with the same domain and permission type as the draft, overwrite the existing permission with fields from the draft.
|
||||||
|
in: formData
|
||||||
|
name: overwrite
|
||||||
|
type: boolean
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The newly created domain permission.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domainPermission'
|
||||||
|
"400":
|
||||||
|
description: bad request
|
||||||
|
"401":
|
||||||
|
description: unauthorized
|
||||||
|
"403":
|
||||||
|
description: forbidden
|
||||||
|
"406":
|
||||||
|
description: not acceptable
|
||||||
|
"409":
|
||||||
|
description: conflict
|
||||||
|
"500":
|
||||||
|
description: internal server error
|
||||||
|
security:
|
||||||
|
- OAuth2 Bearer:
|
||||||
|
- admin
|
||||||
|
summary: Accept a domain permission draft, turning it into an enforced domain permission.
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
|
/api/v1/admin/domain_permission_drafts/{id}/remove:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
- application/json
|
||||||
|
operationId: domainPermissionDraftRemove
|
||||||
|
parameters:
|
||||||
|
- description: ID of the domain permission draft.
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- default: false
|
||||||
|
description: When removing the domain permission draft, also create a domain ignore entry for the target domain, so that drafts will not be created for this domain in the future.
|
||||||
|
in: formData
|
||||||
|
name: ignore_target
|
||||||
|
type: boolean
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: The removed domain permission draft.
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domainPermission'
|
||||||
|
"400":
|
||||||
|
description: bad request
|
||||||
|
"401":
|
||||||
|
description: unauthorized
|
||||||
|
"403":
|
||||||
|
description: forbidden
|
||||||
|
"406":
|
||||||
|
description: not acceptable
|
||||||
|
"409":
|
||||||
|
description: conflict
|
||||||
|
"500":
|
||||||
|
description: internal server error
|
||||||
|
security:
|
||||||
|
- OAuth2 Bearer:
|
||||||
|
- admin
|
||||||
|
summary: Remove a domain permission draft, optionally ignoring all future drafts targeting the given domain.
|
||||||
|
tags:
|
||||||
|
- admin
|
||||||
/api/v1/admin/email/test:
|
/api/v1/admin/email/test:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
@ -36,6 +36,10 @@
|
||||||
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
DomainBlocksPathWithID = DomainBlocksPath + "/:" + apiutil.IDKey
|
||||||
DomainAllowsPath = BasePath + "/domain_allows"
|
DomainAllowsPath = BasePath + "/domain_allows"
|
||||||
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
DomainAllowsPathWithID = DomainAllowsPath + "/:" + apiutil.IDKey
|
||||||
|
DomainPermissionDraftsPath = BasePath + "/domain_permission_drafts"
|
||||||
|
DomainPermissionDraftsPathWithID = DomainPermissionDraftsPath + "/:" + apiutil.IDKey
|
||||||
|
DomainPermissionDraftAcceptPath = DomainPermissionDraftsPathWithID + "/accept"
|
||||||
|
DomainPermissionDraftRemovePath = DomainPermissionDraftsPathWithID + "/remove"
|
||||||
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
DomainKeysExpirePath = BasePath + "/domain_keys_expire"
|
||||||
HeaderAllowsPath = BasePath + "/header_allows"
|
HeaderAllowsPath = BasePath + "/header_allows"
|
||||||
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
HeaderAllowsPathWithID = HeaderAllowsPath + "/:" + apiutil.IDKey
|
||||||
|
@ -99,6 +103,13 @@ func (m *Module) Route(attachHandler func(method string, path string, f ...gin.H
|
||||||
attachHandler(http.MethodGet, DomainAllowsPathWithID, m.DomainAllowGETHandler)
|
attachHandler(http.MethodGet, DomainAllowsPathWithID, m.DomainAllowGETHandler)
|
||||||
attachHandler(http.MethodDelete, DomainAllowsPathWithID, m.DomainAllowDELETEHandler)
|
attachHandler(http.MethodDelete, DomainAllowsPathWithID, m.DomainAllowDELETEHandler)
|
||||||
|
|
||||||
|
// domain permission draft stuff
|
||||||
|
attachHandler(http.MethodGet, DomainPermissionDraftsPath, m.DomainPermissionDraftsPOSTHandler)
|
||||||
|
attachHandler(http.MethodGet, DomainPermissionDraftsPath, m.DomainPermissionDraftsGETHandler)
|
||||||
|
attachHandler(http.MethodGet, DomainPermissionDraftsPathWithID, m.DomainPermissionDraftGETHandler)
|
||||||
|
attachHandler(http.MethodPost, DomainPermissionDraftAcceptPath, m.DomainPermissionDraftAcceptPOSTHandler)
|
||||||
|
attachHandler(http.MethodPost, DomainPermissionDraftRemovePath, m.DomainPermissionDraftRemovePOSTHandler)
|
||||||
|
|
||||||
// header filtering administration routes
|
// header filtering administration routes
|
||||||
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
|
attachHandler(http.MethodGet, HeaderAllowsPathWithID, m.HeaderFilterAllowGET)
|
||||||
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
|
attachHandler(http.MethodGet, HeaderBlocksPathWithID, m.HeaderFilterBlockGET)
|
||||||
|
|
|
@ -78,6 +78,11 @@ func (m *Module) DomainPermissionDraftGETHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if authed.Account.IsMoving() {
|
||||||
|
apiutil.ForbiddenAfterMove(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
return
|
return
|
||||||
|
|
|
@ -18,15 +18,12 @@
|
||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
|
|
||||||
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,6 +35,10 @@
|
||||||
// tags:
|
// tags:
|
||||||
// - admin
|
// - admin
|
||||||
//
|
//
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
//
|
//
|
||||||
|
@ -48,6 +49,15 @@
|
||||||
// in: path
|
// in: path
|
||||||
// description: ID of the domain permission draft.
|
// description: ID of the domain permission draft.
|
||||||
// type: string
|
// type: string
|
||||||
|
// -
|
||||||
|
// name: overwrite
|
||||||
|
// in: formData
|
||||||
|
// description: >-
|
||||||
|
// If a domain permission already exists with the same
|
||||||
|
// domain and permission type as the draft, overwrite
|
||||||
|
// the existing permission with fields from the draft.
|
||||||
|
// type: boolean
|
||||||
|
// default: false
|
||||||
//
|
//
|
||||||
// security:
|
// security:
|
||||||
// - OAuth2 Bearer:
|
// - OAuth2 Bearer:
|
||||||
|
@ -83,6 +93,11 @@ func (m *Module) DomainPermissionDraftAcceptPOSTHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if authed.Account.IsMoving() {
|
||||||
|
apiutil.ForbiddenAfterMove(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
return
|
return
|
||||||
|
@ -94,14 +109,26 @@ func (m *Module) DomainPermissionDraftAcceptPOSTHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
permDraft, actionID, errWithCode := m.processor.Admin().DomainPermissionDraftAccept(
|
type AcceptForm struct {
|
||||||
|
Overwrite bool `json:"overwrite" form:"overwrite"`
|
||||||
|
}
|
||||||
|
|
||||||
|
form := new(AcceptForm)
|
||||||
|
if err := c.ShouldBind(form); err != nil {
|
||||||
|
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domainPerm, _, errWithCode := m.processor.Admin().DomainPermissionDraftAccept(
|
||||||
c.Request.Context(),
|
c.Request.Context(),
|
||||||
authed.Account,
|
authed.Account,
|
||||||
id,
|
id,
|
||||||
c.Form
|
form.Overwrite,
|
||||||
)
|
)
|
||||||
if errWithCode != nil {
|
if errWithCode != nil {
|
||||||
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiutil.JSON(c, http.StatusOK, domainPerm)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
//
|
//
|
||||||
// consumes:
|
// consumes:
|
||||||
// - multipart/form-data
|
// - multipart/form-data
|
||||||
|
// - application/json
|
||||||
//
|
//
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
|
|
134
internal/api/client/admin/domainpermissiondraftremove.go
Normal file
134
internal/api/client/admin/domainpermissiondraftremove.go
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// GoToSocial
|
||||||
|
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
apiutil "github.com/superseriousbusiness/gotosocial/internal/api/util"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/oauth"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DomainPermissionDraftRemovePOSTHandler swagger:operation POST /api/v1/admin/domain_permission_drafts/{id}/remove domainPermissionDraftRemove
|
||||||
|
//
|
||||||
|
// Remove a domain permission draft, optionally ignoring all future drafts targeting the given domain.
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// tags:
|
||||||
|
// - admin
|
||||||
|
//
|
||||||
|
// consumes:
|
||||||
|
// - multipart/form-data
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
|
//
|
||||||
|
// parameters:
|
||||||
|
// -
|
||||||
|
// name: id
|
||||||
|
// required: true
|
||||||
|
// in: path
|
||||||
|
// description: ID of the domain permission draft.
|
||||||
|
// type: string
|
||||||
|
// -
|
||||||
|
// name: ignore_target
|
||||||
|
// in: formData
|
||||||
|
// description: >-
|
||||||
|
// When removing the domain permission draft, also create a
|
||||||
|
// domain ignore entry for the target domain, so that drafts
|
||||||
|
// will not be created for this domain in the future.
|
||||||
|
// type: boolean
|
||||||
|
// default: false
|
||||||
|
//
|
||||||
|
// security:
|
||||||
|
// - OAuth2 Bearer:
|
||||||
|
// - admin
|
||||||
|
//
|
||||||
|
// responses:
|
||||||
|
// '200':
|
||||||
|
// description: The removed domain permission draft.
|
||||||
|
// schema:
|
||||||
|
// "$ref": "#/definitions/domainPermission"
|
||||||
|
// '400':
|
||||||
|
// description: bad request
|
||||||
|
// '401':
|
||||||
|
// description: unauthorized
|
||||||
|
// '403':
|
||||||
|
// description: forbidden
|
||||||
|
// '406':
|
||||||
|
// description: not acceptable
|
||||||
|
// '409':
|
||||||
|
// description: conflict
|
||||||
|
// '500':
|
||||||
|
// description: internal server error
|
||||||
|
func (m *Module) DomainPermissionDraftRemovePOSTHandler(c *gin.Context) {
|
||||||
|
authed, err := oauth.Authed(c, true, true, true, true)
|
||||||
|
if err != nil {
|
||||||
|
apiutil.ErrorHandler(c, gtserror.NewErrorUnauthorized(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !*authed.User.Admin {
|
||||||
|
err := fmt.Errorf("user %s not an admin", authed.User.ID)
|
||||||
|
apiutil.ErrorHandler(c, gtserror.NewErrorForbidden(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if authed.Account.IsMoving() {
|
||||||
|
apiutil.ForbiddenAfterMove(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||||
|
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
id, errWithCode := apiutil.ParseID(c.Param(apiutil.IDKey))
|
||||||
|
if errWithCode != nil {
|
||||||
|
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type RemoveForm struct {
|
||||||
|
IgnoreTarget bool `json:"ignore_target" form:"ignore_target"`
|
||||||
|
}
|
||||||
|
|
||||||
|
form := new(RemoveForm)
|
||||||
|
if err := c.ShouldBind(form); err != nil {
|
||||||
|
apiutil.ErrorHandler(c, gtserror.NewErrorBadRequest(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domainPerm, errWithCode := m.processor.Admin().DomainPermissionDraftRemove(
|
||||||
|
c.Request.Context(),
|
||||||
|
authed.Account,
|
||||||
|
id,
|
||||||
|
form.IgnoreTarget,
|
||||||
|
)
|
||||||
|
if errWithCode != nil {
|
||||||
|
apiutil.ErrorHandler(c, errWithCode, m.processor.InstanceGetV1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
apiutil.JSON(c, http.StatusOK, domainPerm)
|
||||||
|
}
|
|
@ -137,6 +137,11 @@ func (m *Module) DomainPermissionDraftsGETHandler(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if authed.Account.IsMoving() {
|
||||||
|
apiutil.ForbiddenAfterMove(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
if _, err := apiutil.NegotiateAccept(c, apiutil.JSONAcceptHeaders...); err != nil {
|
||||||
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
apiutil.ErrorHandler(c, gtserror.NewErrorNotAcceptable(err, err.Error()), m.processor.InstanceGetV1)
|
||||||
return
|
return
|
||||||
|
|
|
@ -65,7 +65,7 @@ type DomainPermission struct {
|
||||||
|
|
||||||
// DomainPermissionSubscription represents an auto-refreshing subscription to a list of domain permissions (allows, blocks).
|
// DomainPermissionSubscription represents an auto-refreshing subscription to a list of domain permissions (allows, blocks).
|
||||||
//
|
//
|
||||||
// swagger:model domainPermission
|
// swagger:model domainPermissionSubscription
|
||||||
type DomainPermissionSubscription struct {
|
type DomainPermissionSubscription struct {
|
||||||
// The ID of the domain permission subscription.
|
// The ID of the domain permission subscription.
|
||||||
// example: 01FBW21XJA09XYX51KV5JVBW0F
|
// example: 01FBW21XJA09XYX51KV5JVBW0F
|
||||||
|
|
|
@ -19,19 +19,13 @@
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"slices"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/config"
|
"github.com/superseriousbusiness/gotosocial/internal/config"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/db"
|
"github.com/superseriousbusiness/gotosocial/internal/db"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
|
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
|
"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/state"
|
||||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
"github.com/uptrace/bun"
|
"github.com/uptrace/bun"
|
||||||
|
@ -395,701 +389,3 @@ func (d *domainDB) AreURIsBlocked(ctx context.Context, uris []*url.URL) (bool, e
|
||||||
}
|
}
|
||||||
return false, nil
|
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
|
|
||||||
}
|
|
||||||
|
|
285
internal/db/bundb/domainpermissiondraft.go
Normal file
285
internal/db/bundb/domainpermissiondraft.go
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
// 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/superseriousbusiness/gotosocial/internal/util"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
275
internal/db/bundb/domainpermissionignore.go
Normal file
275
internal/db/bundb/domainpermissionignore.go
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
// 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/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/util"
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
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,
|
||||||
|
domain string,
|
||||||
|
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 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_ignore.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_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
|
||||||
|
}
|
246
internal/db/bundb/domainpermissionsubscription.go
Normal file
246
internal/db/bundb/domainpermissionsubscription.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -109,6 +109,27 @@ type Domain interface {
|
||||||
// DeleteDomainPermissionDraft deletes one DomainPermissionDraft with the given id.
|
// DeleteDomainPermissionDraft deletes one DomainPermissionDraft with the given id.
|
||||||
DeleteDomainPermissionDraft(ctx context.Context, id string) error
|
DeleteDomainPermissionDraft(ctx context.Context, id string) error
|
||||||
|
|
||||||
|
/*
|
||||||
|
Domain permission ignore stuff.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// GetDomainPermissionIgnoreByID gets one DomainPermissionIgnore with the given ID.
|
||||||
|
GetDomainPermissionIgnoreByID(ctx context.Context, id string) (*gtsmodel.DomainPermissionIgnore, error)
|
||||||
|
|
||||||
|
// GetDomainPermissionIgnores returns a page of
|
||||||
|
// DomainPermissionIgnores using the given parameters.
|
||||||
|
GetDomainPermissionIgnores(
|
||||||
|
ctx context.Context,
|
||||||
|
domain string,
|
||||||
|
page *paging.Page,
|
||||||
|
) ([]*gtsmodel.DomainPermissionIgnore, error)
|
||||||
|
|
||||||
|
// PutDomainPermissionIgnore stores one DomainPermissionIgnore.
|
||||||
|
PutDomainPermissionIgnore(ctx context.Context, permIgnore *gtsmodel.DomainPermissionIgnore) error
|
||||||
|
|
||||||
|
// DeleteDomainPermissionIgnore deletes one DomainPermissionIgnore with the given id.
|
||||||
|
DeleteDomainPermissionIgnore(ctx context.Context, id string) error
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Domain permission subscription stuff.
|
Domain permission subscription stuff.
|
||||||
*/
|
*/
|
||||||
|
@ -120,7 +141,7 @@ type Domain interface {
|
||||||
// DomainPermissionSubscriptions using the given parameters.
|
// DomainPermissionSubscriptions using the given parameters.
|
||||||
GetDomainPermissionSubscriptions(
|
GetDomainPermissionSubscriptions(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType *gtsmodel.DomainPermissionType,
|
permType gtsmodel.DomainPermissionType,
|
||||||
page *paging.Page,
|
page *paging.Page,
|
||||||
) ([]*gtsmodel.DomainPermissionSubscription, error)
|
) ([]*gtsmodel.DomainPermissionSubscription, error)
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// DomainPermission models a domain
|
// DomainPermission models a domain permission
|
||||||
// permission entry (block/allow/draft).
|
// entry -- block / allow / draft / ignore.
|
||||||
type DomainPermission interface {
|
type DomainPermission interface {
|
||||||
GetID() string
|
GetID() string
|
||||||
GetCreatedAt() time.Time
|
GetCreatedAt() time.Time
|
||||||
|
|
|
@ -17,16 +17,76 @@
|
||||||
|
|
||||||
package gtsmodel
|
package gtsmodel
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||||
|
)
|
||||||
|
|
||||||
// DomainPermissionIgnore represents one domain that should be ignored
|
// DomainPermissionIgnore represents one domain that should be ignored
|
||||||
// when domain permission (ignores) are created from subscriptions.
|
// when domain permission (ignores) are created from subscriptions.
|
||||||
type DomainPermissionIgnore struct {
|
type DomainPermissionIgnore struct {
|
||||||
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // ID of this item in the database.
|
ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // ID of this item in the database.
|
||||||
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was created.
|
CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was created.
|
||||||
PermissionType DomainPermissionType `bun:",notnull,unique:domain_permission_ignores_permission_type_domain_uniq"` // Permission type of the ignore.
|
UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // Time when this item was last updated.
|
||||||
Domain string `bun:",nullzero,notnull,unique:domain_permission_ignores_permission_type_domain_uniq"` // Domain to ignore. Eg. 'whatever.com'.
|
Domain string `bun:",nullzero,notnull,unique"` // Domain to ignore. Eg. 'whatever.com'.
|
||||||
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this ignore.
|
CreatedByAccountID string `bun:"type:CHAR(26),nullzero,notnull"` // Account ID of the creator of this ignore.
|
||||||
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
CreatedByAccount *Account `bun:"-"` // Account corresponding to createdByAccountID.
|
||||||
PrivateComment string `bun:",nullzero"` // Private comment on this ignore, viewable to admins.
|
PrivateComment string `bun:",nullzero"` // Private comment on this ignore, viewable to admins.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetID() string {
|
||||||
|
return d.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetCreatedAt() time.Time {
|
||||||
|
return d.CreatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetUpdatedAt() time.Time {
|
||||||
|
return d.UpdatedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) SetUpdatedAt(i time.Time) {
|
||||||
|
d.UpdatedAt = i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetDomain() string {
|
||||||
|
return d.Domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetCreatedByAccountID() string {
|
||||||
|
return d.CreatedByAccountID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) SetCreatedByAccountID(i string) {
|
||||||
|
d.CreatedByAccountID = i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetCreatedByAccount() *Account {
|
||||||
|
return d.CreatedByAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) SetCreatedByAccount(i *Account) {
|
||||||
|
d.CreatedByAccount = i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetPrivateComment() string {
|
||||||
|
return d.PrivateComment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) SetPrivateComment(i string) {
|
||||||
|
d.PrivateComment = i
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Stubbed functions for interface purposes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (d *DomainPermissionIgnore) GetPublicComment() string { return "" }
|
||||||
|
func (d *DomainPermissionIgnore) SetPublicComment(_ string) {}
|
||||||
|
func (d *DomainPermissionIgnore) GetObfuscate() *bool { return util.Ptr(false) }
|
||||||
|
func (d *DomainPermissionIgnore) SetObfuscate(_ *bool) {}
|
||||||
|
func (d *DomainPermissionIgnore) GetSubscriptionID() string { return "" }
|
||||||
|
func (d *DomainPermissionIgnore) SetSubscriptionID(_ string) {}
|
||||||
|
func (d *DomainPermissionIgnore) GetType() DomainPermissionType { return DomainPermissionUnknown }
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
// from this call, and/or an error if something goes wrong.
|
// from this call, and/or an error if something goes wrong.
|
||||||
func (p *Processor) DomainPermissionCreate(
|
func (p *Processor) DomainPermissionCreate(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
adminAcct *gtsmodel.Account,
|
adminAcct *gtsmodel.Account,
|
||||||
domain string,
|
domain string,
|
||||||
obfuscate bool,
|
obfuscate bool,
|
||||||
|
@ -51,7 +51,7 @@ func (p *Processor) DomainPermissionCreate(
|
||||||
privateComment string,
|
privateComment string,
|
||||||
subscriptionID string,
|
subscriptionID string,
|
||||||
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
||||||
switch permType {
|
switch permissionType {
|
||||||
|
|
||||||
// Explicitly block a domain.
|
// Explicitly block a domain.
|
||||||
case gtsmodel.DomainPermissionBlock:
|
case gtsmodel.DomainPermissionBlock:
|
||||||
|
@ -79,7 +79,7 @@ func (p *Processor) DomainPermissionCreate(
|
||||||
|
|
||||||
// Weeping, roaring, red-faced.
|
// Weeping, roaring, red-faced.
|
||||||
default:
|
default:
|
||||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||||
return nil, "", gtserror.NewErrorInternalError(err)
|
return nil, "", gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,11 +91,11 @@ func (p *Processor) DomainPermissionCreate(
|
||||||
// action resulting from this call, and/or an error if something goes wrong.
|
// action resulting from this call, and/or an error if something goes wrong.
|
||||||
func (p *Processor) DomainPermissionDelete(
|
func (p *Processor) DomainPermissionDelete(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
adminAcct *gtsmodel.Account,
|
adminAcct *gtsmodel.Account,
|
||||||
domainBlockID string,
|
domainBlockID string,
|
||||||
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
||||||
switch permType {
|
switch permissionType {
|
||||||
|
|
||||||
// Delete explicit domain block.
|
// Delete explicit domain block.
|
||||||
case gtsmodel.DomainPermissionBlock:
|
case gtsmodel.DomainPermissionBlock:
|
||||||
|
@ -116,7 +116,7 @@ func (p *Processor) DomainPermissionDelete(
|
||||||
// You do the hokey-cokey and you turn
|
// You do the hokey-cokey and you turn
|
||||||
// around, that's what it's all about.
|
// around, that's what it's all about.
|
||||||
default:
|
default:
|
||||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||||
return nil, "", gtserror.NewErrorInternalError(err)
|
return nil, "", gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,14 +134,14 @@ func (p *Processor) DomainPermissionDelete(
|
||||||
// as they wish.
|
// as they wish.
|
||||||
func (p *Processor) DomainPermissionsImport(
|
func (p *Processor) DomainPermissionsImport(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
account *gtsmodel.Account,
|
account *gtsmodel.Account,
|
||||||
domainsF *multipart.FileHeader,
|
domainsF *multipart.FileHeader,
|
||||||
) (*apimodel.MultiStatus, gtserror.WithCode) {
|
) (*apimodel.MultiStatus, gtserror.WithCode) {
|
||||||
// Ensure known permission type.
|
// Ensure known permission type.
|
||||||
if permType != gtsmodel.DomainPermissionBlock &&
|
if permissionType != gtsmodel.DomainPermissionBlock &&
|
||||||
permType != gtsmodel.DomainPermissionAllow {
|
permissionType != gtsmodel.DomainPermissionAllow {
|
||||||
err := gtserror.Newf("unrecognized permission type %d", permType)
|
err := gtserror.Newf("unrecognized permission type %d", permissionType)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ func (p *Processor) DomainPermissionsImport(
|
||||||
|
|
||||||
domainPerm, _, errWithCode = p.DomainPermissionCreate(
|
domainPerm, _, errWithCode = p.DomainPermissionCreate(
|
||||||
ctx,
|
ctx,
|
||||||
permType,
|
permissionType,
|
||||||
account,
|
account,
|
||||||
domain,
|
domain,
|
||||||
obfuscate,
|
obfuscate,
|
||||||
|
@ -222,7 +222,7 @@ func (p *Processor) DomainPermissionsImport(
|
||||||
// to an export.
|
// to an export.
|
||||||
func (p *Processor) DomainPermissionsGet(
|
func (p *Processor) DomainPermissionsGet(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
account *gtsmodel.Account,
|
account *gtsmodel.Account,
|
||||||
export bool,
|
export bool,
|
||||||
) ([]*apimodel.DomainPermission, gtserror.WithCode) {
|
) ([]*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
|
@ -231,7 +231,7 @@ func (p *Processor) DomainPermissionsGet(
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
switch permType {
|
switch permissionType {
|
||||||
case gtsmodel.DomainPermissionBlock:
|
case gtsmodel.DomainPermissionBlock:
|
||||||
var blocks []*gtsmodel.DomainBlock
|
var blocks []*gtsmodel.DomainBlock
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@ func (p *Processor) DomainPermissionsGet(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := gtserror.Newf("error getting %ss: %w", permType.String(), err)
|
err := gtserror.Newf("error getting %ss: %w", permissionType.String(), err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ func (p *Processor) DomainPermissionsGet(
|
||||||
// suitable for writing out to an export.
|
// suitable for writing out to an export.
|
||||||
func (p *Processor) DomainPermissionGet(
|
func (p *Processor) DomainPermissionGet(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
id string,
|
id string,
|
||||||
export bool,
|
export bool,
|
||||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
|
@ -294,7 +294,7 @@ func (p *Processor) DomainPermissionGet(
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
switch permType {
|
switch permissionType {
|
||||||
case gtsmodel.DomainPermissionBlock:
|
case gtsmodel.DomainPermissionBlock:
|
||||||
domainPerm, err = p.state.DB.GetDomainBlockByID(ctx, id)
|
domainPerm, err = p.state.DB.GetDomainBlockByID(ctx, id)
|
||||||
case gtsmodel.DomainPermissionAllow:
|
case gtsmodel.DomainPermissionAllow:
|
||||||
|
@ -305,11 +305,11 @@ func (p *Processor) DomainPermissionGet(
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, db.ErrNoEntries) {
|
if errors.Is(err, db.ErrNoEntries) {
|
||||||
err = fmt.Errorf("no domain %s exists with id %s", permType.String(), id)
|
err = fmt.Errorf("no domain %s exists with id %s", permissionType.String(), id)
|
||||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gtserror.Newf("error getting domain %s with id %s: %w", permType.String(), id, err)
|
err = gtserror.Newf("error getting domain %s with id %s: %w", permissionType.String(), id, err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ type domainPermAction struct {
|
||||||
|
|
||||||
// Type of permission
|
// Type of permission
|
||||||
// to create or delete.
|
// to create or delete.
|
||||||
permType gtsmodel.DomainPermissionType
|
permissionType gtsmodel.DomainPermissionType
|
||||||
|
|
||||||
// Domain to target
|
// Domain to target
|
||||||
// with the permission.
|
// with the permission.
|
||||||
|
@ -89,9 +89,9 @@ func (suite *DomainBlockTestSuite) runDomainPermTest(t domainPermTest) {
|
||||||
var actionID string
|
var actionID string
|
||||||
switch action.createOrDelete {
|
switch action.createOrDelete {
|
||||||
case "create":
|
case "create":
|
||||||
_, actionID = suite.createDomainPerm(action.permType, action.domain)
|
_, actionID = suite.createDomainPerm(action.permissionType, action.domain)
|
||||||
case "delete":
|
case "delete":
|
||||||
_, actionID = suite.deleteDomainPerm(action.permType, action.domain)
|
_, actionID = suite.deleteDomainPerm(action.permissionType, action.domain)
|
||||||
default:
|
default:
|
||||||
panic("createOrDelete was not 'create' or 'delete'")
|
panic("createOrDelete was not 'create' or 'delete'")
|
||||||
}
|
}
|
||||||
|
@ -118,16 +118,16 @@ func (suite *DomainBlockTestSuite) runDomainPermTest(t domainPermTest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create given permType with default values.
|
// create given permissionType with default values.
|
||||||
func (suite *DomainBlockTestSuite) createDomainPerm(
|
func (suite *DomainBlockTestSuite) createDomainPerm(
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
domain string,
|
domain string,
|
||||||
) (*apimodel.DomainPermission, string) {
|
) (*apimodel.DomainPermission, string) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionCreate(
|
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionCreate(
|
||||||
ctx,
|
ctx,
|
||||||
permType,
|
permissionType,
|
||||||
suite.testAccounts["admin_account"],
|
suite.testAccounts["admin_account"],
|
||||||
domain,
|
domain,
|
||||||
false,
|
false,
|
||||||
|
@ -144,7 +144,7 @@ func (suite *DomainBlockTestSuite) createDomainPerm(
|
||||||
|
|
||||||
// delete given permission type.
|
// delete given permission type.
|
||||||
func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
||||||
permType gtsmodel.DomainPermissionType,
|
permissionType gtsmodel.DomainPermissionType,
|
||||||
domain string,
|
domain string,
|
||||||
) (*apimodel.DomainPermission, string) {
|
) (*apimodel.DomainPermission, string) {
|
||||||
var (
|
var (
|
||||||
|
@ -154,7 +154,7 @@ func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
||||||
|
|
||||||
// To delete the permission,
|
// To delete the permission,
|
||||||
// first get it from the db.
|
// first get it from the db.
|
||||||
switch permType {
|
switch permissionType {
|
||||||
case gtsmodel.DomainPermissionBlock:
|
case gtsmodel.DomainPermissionBlock:
|
||||||
domainPermission, _ = suite.db.GetDomainBlock(ctx, domain)
|
domainPermission, _ = suite.db.GetDomainBlock(ctx, domain)
|
||||||
case gtsmodel.DomainPermissionAllow:
|
case gtsmodel.DomainPermissionAllow:
|
||||||
|
@ -170,7 +170,7 @@ func (suite *DomainBlockTestSuite) deleteDomainPerm(
|
||||||
// Now use the ID to delete it.
|
// Now use the ID to delete it.
|
||||||
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionDelete(
|
apiPerm, actionID, errWithCode := suite.adminProcessor.DomainPermissionDelete(
|
||||||
ctx,
|
ctx,
|
||||||
permType,
|
permissionType,
|
||||||
suite.testAccounts["admin_account"],
|
suite.testAccounts["admin_account"],
|
||||||
domainPermission.GetID(),
|
domainPermission.GetID(),
|
||||||
)
|
)
|
||||||
|
@ -246,7 +246,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndUnblockDomain() {
|
||||||
actions: []domainPermAction{
|
actions: []domainPermAction{
|
||||||
{
|
{
|
||||||
createOrDelete: "create",
|
createOrDelete: "create",
|
||||||
permType: gtsmodel.DomainPermissionBlock,
|
permissionType: gtsmodel.DomainPermissionBlock,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
||||||
// Domain was blocked, so each
|
// Domain was blocked, so each
|
||||||
|
@ -256,7 +256,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndUnblockDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "delete",
|
createOrDelete: "delete",
|
||||||
permType: gtsmodel.DomainPermissionBlock,
|
permissionType: gtsmodel.DomainPermissionBlock,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
expected: func(_ context.Context, account *gtsmodel.Account) bool {
|
||||||
// Domain was unblocked, so each
|
// Domain was unblocked, so each
|
||||||
|
@ -279,7 +279,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
||||||
actions: []domainPermAction{
|
actions: []domainPermAction{
|
||||||
{
|
{
|
||||||
createOrDelete: "create",
|
createOrDelete: "create",
|
||||||
permType: gtsmodel.DomainPermissionBlock,
|
permissionType: gtsmodel.DomainPermissionBlock,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Domain was blocked, so each
|
// Domain was blocked, so each
|
||||||
|
@ -316,7 +316,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "create",
|
createOrDelete: "create",
|
||||||
permType: gtsmodel.DomainPermissionAllow,
|
permissionType: gtsmodel.DomainPermissionAllow,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Domain was explicitly allowed, so each
|
// Domain was explicitly allowed, so each
|
||||||
|
@ -355,7 +355,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "delete",
|
createOrDelete: "delete",
|
||||||
permType: gtsmodel.DomainPermissionAllow,
|
permissionType: gtsmodel.DomainPermissionAllow,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Deleting the allow now, while there's
|
// Deleting the allow now, while there's
|
||||||
|
@ -382,7 +382,7 @@ func (suite *DomainBlockTestSuite) TestBlockAndAllowDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "delete",
|
createOrDelete: "delete",
|
||||||
permType: gtsmodel.DomainPermissionBlock,
|
permissionType: gtsmodel.DomainPermissionBlock,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Deleting the block now should
|
// Deleting the block now should
|
||||||
|
@ -421,7 +421,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
||||||
actions: []domainPermAction{
|
actions: []domainPermAction{
|
||||||
{
|
{
|
||||||
createOrDelete: "create",
|
createOrDelete: "create",
|
||||||
permType: gtsmodel.DomainPermissionAllow,
|
permissionType: gtsmodel.DomainPermissionAllow,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Domain was explicitly allowed,
|
// Domain was explicitly allowed,
|
||||||
|
@ -458,7 +458,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "create",
|
createOrDelete: "create",
|
||||||
permType: gtsmodel.DomainPermissionBlock,
|
permissionType: gtsmodel.DomainPermissionBlock,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Create a block. An allow existed, so
|
// Create a block. An allow existed, so
|
||||||
|
@ -497,7 +497,7 @@ func (suite *DomainBlockTestSuite) TestAllowAndBlockDomain() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
createOrDelete: "delete",
|
createOrDelete: "delete",
|
||||||
permType: gtsmodel.DomainPermissionAllow,
|
permissionType: gtsmodel.DomainPermissionAllow,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
expected: func(ctx context.Context, account *gtsmodel.Account) bool {
|
||||||
// Deleting the allow now, while there's
|
// Deleting the allow now, while there's
|
||||||
|
|
|
@ -42,12 +42,12 @@ func (p *Processor) DomainPermissionDraftGet(
|
||||||
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
err = gtserror.Newf("db error getting domain permission draft %s: %w", id, err)
|
err := gtserror.Newf("db error getting domain permission draft %s: %w", id, err)
|
||||||
return nil, gtserror.NewErrorInternalError(err)
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if permDraft == nil {
|
if permDraft == nil {
|
||||||
err = fmt.Errorf("domain permission draft %s not found", id)
|
err := fmt.Errorf("domain permission draft %s not found", id)
|
||||||
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +138,9 @@ func (p *Processor) DomainPermissionDraftCreate(
|
||||||
|
|
||||||
if err := p.state.DB.PutDomainPermissionDraft(ctx, permDraft); err != nil {
|
if err := p.state.DB.PutDomainPermissionDraft(ctx, permDraft); err != nil {
|
||||||
if errors.Is(err, db.ErrAlreadyExists) {
|
if errors.Is(err, db.ErrAlreadyExists) {
|
||||||
const text = "a domain permission draft already exists with this permission type and domain"
|
const text = "a domain permission draft already exists with this permission type, domain, and subscription ID"
|
||||||
return nil, gtserror.NewErrorConflict(errors.New(text), text)
|
err := fmt.Errorf("%w: %s", err, text)
|
||||||
|
return nil, gtserror.NewErrorConflict(err, text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Real error.
|
// Real error.
|
||||||
|
@ -158,12 +159,12 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
) (*apimodel.DomainPermission, string, gtserror.WithCode) {
|
||||||
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
permDraft, err := p.state.DB.GetDomainPermissionDraftByID(ctx, id)
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
err = gtserror.Newf("db error getting domain permission draft %s: %w", id, err)
|
err := gtserror.Newf("db error getting domain permission draft %s: %w", id, err)
|
||||||
return nil, "", gtserror.NewErrorInternalError(err)
|
return nil, "", gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if permDraft == nil {
|
if permDraft == nil {
|
||||||
err = fmt.Errorf("domain permission draft %s not found", id)
|
err := fmt.Errorf("domain permission draft %s not found", id)
|
||||||
return nil, "", gtserror.NewErrorNotFound(err, err.Error())
|
return nil, "", gtserror.NewErrorNotFound(err, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +189,7 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
err = gtserror.Newf("db error getting domain permission %s: %w", id, err)
|
err := gtserror.Newf("db error getting domain permission %s: %w", id, err)
|
||||||
return nil, "", gtserror.NewErrorInternalError(err)
|
return nil, "", gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
// creating or updating permission from draft is successful.
|
// creating or updating permission from draft is successful.
|
||||||
deleteDraft := func() {
|
deleteDraft := func() {
|
||||||
if err := p.state.DB.DeleteDomainPermissionDraft(ctx, permDraft.ID); err != nil {
|
if err := p.state.DB.DeleteDomainPermissionDraft(ctx, permDraft.ID); err != nil {
|
||||||
log.Errorf(ctx, "error deleting domain permission draft: %v", err)
|
log.Errorf(ctx, "db error deleting domain permission draft: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +236,10 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up the draft
|
||||||
|
// before returning.
|
||||||
deleteDraft()
|
deleteDraft()
|
||||||
|
|
||||||
return new, actionID, errWithCode
|
return new, actionID, errWithCode
|
||||||
|
|
||||||
// Domain permission exists but we should overwrite
|
// Domain permission exists but we should overwrite
|
||||||
|
@ -259,10 +263,12 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = gtserror.Newf("db error updating existing domain permission: %w", err)
|
err := gtserror.Newf("db error updating existing domain permission: %w", err)
|
||||||
return nil, "", gtserror.NewErrorInternalError(err)
|
return nil, "", gtserror.NewErrorInternalError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up the draft
|
||||||
|
// before returning.
|
||||||
deleteDraft()
|
deleteDraft()
|
||||||
|
|
||||||
apiPerm, errWithCode := p.apiDomainPerm(ctx, existing, false)
|
apiPerm, errWithCode := p.apiDomainPerm(ctx, existing, false)
|
||||||
|
@ -272,6 +278,48 @@ func (p *Processor) DomainPermissionDraftAccept(
|
||||||
// overwrite it, leave everything alone.
|
// overwrite it, leave everything alone.
|
||||||
default:
|
default:
|
||||||
const text = "a domain permission already exists with this permission type and domain"
|
const text = "a domain permission already exists with this permission type and domain"
|
||||||
return nil, "", gtserror.NewErrorConflict(errors.New(text), text)
|
err := fmt.Errorf("%w: %s", err, text)
|
||||||
|
return nil, "", gtserror.NewErrorConflict(err, text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Processor) DomainPermissionDraftRemove(
|
||||||
|
ctx context.Context,
|
||||||
|
acct *gtsmodel.Account,
|
||||||
|
id string,
|
||||||
|
ignoreTarget bool,
|
||||||
|
) (*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())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the permission draft.
|
||||||
|
if err := p.state.DB.DeleteDomainPermissionDraft(ctx, permDraft.ID); err != nil {
|
||||||
|
err := gtserror.Newf("db error deleting domain permission draft: %w", err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ignoreTarget {
|
||||||
|
// Add a domain permission ignore
|
||||||
|
// targeting the permDraft's domain.
|
||||||
|
_, err = p.DomainPermissionIgnoreCreate(
|
||||||
|
ctx,
|
||||||
|
acct,
|
||||||
|
permDraft.Domain,
|
||||||
|
permDraft.PrivateComment,
|
||||||
|
)
|
||||||
|
if err != nil && !errors.Is(err, db.ErrAlreadyExists) {
|
||||||
|
err := gtserror.Newf("db error creating domain permission ignore: %w", err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.apiDomainPerm(ctx, permDraft, false)
|
||||||
|
}
|
||||||
|
|
134
internal/processing/admin/domainpermissionignore.go
Normal file
134
internal/processing/admin/domainpermissionignore.go
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
// GoToSocial
|
||||||
|
// Copyright (C) GoToSocial Authors admin@gotosocial.org
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Processor) DomainPermissionIgnoreCreate(
|
||||||
|
ctx context.Context,
|
||||||
|
acct *gtsmodel.Account,
|
||||||
|
domain string,
|
||||||
|
privateComment string,
|
||||||
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
|
permIgnore := >smodel.DomainPermissionIgnore{
|
||||||
|
ID: id.NewULID(),
|
||||||
|
Domain: domain,
|
||||||
|
CreatedByAccountID: acct.ID,
|
||||||
|
CreatedByAccount: acct,
|
||||||
|
PrivateComment: privateComment,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.state.DB.PutDomainPermissionIgnore(ctx, permIgnore); err != nil {
|
||||||
|
if errors.Is(err, db.ErrAlreadyExists) {
|
||||||
|
const text = "a domain permission ignore already exists with this permission type and domain"
|
||||||
|
err := fmt.Errorf("%w: %s", err, text)
|
||||||
|
return nil, gtserror.NewErrorConflict(err, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real error.
|
||||||
|
err := gtserror.Newf("db error putting domain permission ignore: %w", err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.apiDomainPerm(ctx, permIgnore, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainPermissionIgnoreGet returns one
|
||||||
|
// domain permission ignore with the given id.
|
||||||
|
func (p *Processor) DomainPermissionIgnoreGet(
|
||||||
|
ctx context.Context,
|
||||||
|
id string,
|
||||||
|
) (*apimodel.DomainPermission, gtserror.WithCode) {
|
||||||
|
permIgnore, err := p.state.DB.GetDomainPermissionIgnoreByID(ctx, id)
|
||||||
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
|
err := gtserror.Newf("db error getting domain permission ignore %s: %w", id, err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if permIgnore == nil {
|
||||||
|
err := fmt.Errorf("domain permission ignore %s not found", id)
|
||||||
|
return nil, gtserror.NewErrorNotFound(err, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.apiDomainPerm(ctx, permIgnore, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainPermissionIgnoresGet returns a page of
|
||||||
|
// DomainPermissionIgnores with the given parameters.
|
||||||
|
func (p *Processor) DomainPermissionIgnoresGet(
|
||||||
|
ctx context.Context,
|
||||||
|
domain string,
|
||||||
|
page *paging.Page,
|
||||||
|
) (*apimodel.PageableResponse, gtserror.WithCode) {
|
||||||
|
permIgnores, err := p.state.DB.GetDomainPermissionIgnores(
|
||||||
|
ctx,
|
||||||
|
domain,
|
||||||
|
page,
|
||||||
|
)
|
||||||
|
if err != nil && !errors.Is(err, db.ErrNoEntries) {
|
||||||
|
err := gtserror.Newf("db error: %w", err)
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count := len(permIgnores)
|
||||||
|
if count == 0 {
|
||||||
|
return paging.EmptyResponse(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the lowest and highest
|
||||||
|
// ID values, used for paging.
|
||||||
|
lo := permIgnores[count-1].ID
|
||||||
|
hi := permIgnores[0].ID
|
||||||
|
|
||||||
|
// Convert each perm ignore to API model.
|
||||||
|
items := make([]any, len(permIgnores))
|
||||||
|
for i, permIgnore := range permIgnores {
|
||||||
|
apiPermIgnore, err := p.apiDomainPerm(ctx, permIgnore, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, gtserror.NewErrorInternalError(err)
|
||||||
|
}
|
||||||
|
items[i] = apiPermIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble next/prev page queries.
|
||||||
|
query := make(url.Values, 1)
|
||||||
|
if domain != "" {
|
||||||
|
query.Set(apiutil.DomainPermissionDomainKey, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
return paging.PackageResponse(paging.ResponseParams{
|
||||||
|
Items: items,
|
||||||
|
Path: "/api/v1/admin/domain_permission_ignores",
|
||||||
|
Next: page.Next(lo, hi),
|
||||||
|
Prev: page.Prev(lo, hi),
|
||||||
|
Query: query,
|
||||||
|
}), nil
|
||||||
|
}
|
|
@ -1937,7 +1937,8 @@ func (c *Converter) ConversationToAPIConversation(
|
||||||
return apiConversation, nil
|
return apiConversation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DomainPermToAPIDomainPerm converts a gts model domin block or allow into an api domain permission.
|
// DomainPermToAPIDomainPerm converts a gtsmodel domain block,
|
||||||
|
// allow, draft, or ignore into an api domain permission.
|
||||||
func (c *Converter) DomainPermToAPIDomainPerm(
|
func (c *Converter) DomainPermToAPIDomainPerm(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
d gtsmodel.DomainPermission,
|
d gtsmodel.DomainPermission,
|
||||||
|
|
|
@ -4134,9 +4134,9 @@ http-parser-js@>=0.5.1:
|
||||||
integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==
|
integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==
|
||||||
|
|
||||||
http-proxy-middleware@^2.0.6:
|
http-proxy-middleware@^2.0.6:
|
||||||
version "2.0.6"
|
version "2.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f"
|
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6"
|
||||||
integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==
|
integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/http-proxy" "^1.17.8"
|
"@types/http-proxy" "^1.17.8"
|
||||||
http-proxy "^1.18.1"
|
http-proxy "^1.18.1"
|
||||||
|
|
Loading…
Reference in a new issue