Skip to content

Commit

Permalink
[feature] Filters v1 (#2594)
Browse files Browse the repository at this point in the history
* Implement client-side v1 filters

* Exclude linter false positives

* Update test/envparsing.sh

* Fix minor Swagger, style, and Bun usage issues

* Regenerate Swagger

* De-generify filter keywords

* Remove updating filter statuses

This is an operation that the Mastodon v2 filter API doesn't actually have, because filter statuses, unlike keywords, don't have options: the only info they contain is the status ID to be filtered.

* Add a test for filter statuses specifically

* De-generify filter statuses

* Inline FilterEntry

* Use vertical style for Bun operations consistently

* Add comment on Filter DB interface

* Remove GoLand linter control comments

Our existing linters should catch these, or they don't matter very much

* Reduce memory ratio for filters
  • Loading branch information
VyrCossont committed Mar 6, 2024
1 parent 7bc536d commit 61a2b91
Show file tree
Hide file tree
Showing 50 changed files with 4,672 additions and 52 deletions.
9 changes: 9 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,12 @@ linters-settings:
# Enable all checks, but disable SA1012: nil context passing.
# See: https://staticcheck.io/docs/configuration/options/#checks
checks: ["all", "-SA1012"]

issues:
exclude-rules:
# Exclude VSCode custom folding region comments in files that use them.
# Already fixed in go-critic and can be removed next time go-critic is updated.
- linters:
- gocritic
path: internal/db/filter.go
text: 'commentFormatting: put a space between `//` and comment text'
297 changes: 297 additions & 0 deletions docs/api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,61 @@ definitions:
type: object
x-go-name: Field
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
filterContext:
description: v1 and v2 filter APIs use the same set of contexts.
title: FilterContext represents the context in which to apply a filter.
type: string
x-go-name: FilterContext
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
filterV1:
description: |-
Note that v1 filters are mapped to v2 filters and v2 filter keywords internally.
If whole_word is true, client app should do:
Define ‘word constituent character’ for your app. In the official implementation, it’s [A-Za-z0-9_] in JavaScript, and [[:word:]] in Ruby.
Ruby uses the POSIX character class (Letter | Mark | Decimal_Number | Connector_Punctuation).
If the phrase starts with a word character, and if the previous character before matched range is a word character, its matched range should be treated to not match.
If the phrase ends with a word character, and if the next character after matched range is a word character, its matched range should be treated to not match.
Please check app/javascript/mastodon/selectors/index.js and app/lib/feed_manager.rb in the Mastodon source code for more details.
properties:
context:
description: The contexts in which the filter should be applied.
example:
- home
- public
items:
$ref: '#/definitions/filterContext'
minLength: 1
type: array
uniqueItems: true
x-go-name: Context
expires_at:
description: When the filter should no longer be applied. Null if the filter does not expire.
example: "2024-02-01T02:57:49Z"
type: string
x-go-name: ExpiresAt
id:
description: The ID of the filter in the database.
type: string
x-go-name: ID
irreversible:
description: Should matching entities be removed from the user's timelines/views, instead of hidden?
example: false
type: boolean
x-go-name: Irreversible
phrase:
description: The text to be filtered.
example: fnord
type: string
x-go-name: Phrase
whole_word:
description: Should the filter consider word boundaries?
example: true
type: boolean
x-go-name: WholeWord
title: FilterV1 represents a user-defined filter for determining which statuses should not be shown to the user.
type: object
x-go-name: FilterV1
x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model
headerFilterCreateRequest:
properties:
header:
Expand Down Expand Up @@ -5570,6 +5625,246 @@ paths:
summary: Get an array of all hashtags that you currently have featured on your profile.
tags:
- featured_tags
/api/v1/filters:
get:
operationId: filtersV1Get
produces:
- application/json
responses:
"200":
description: Requested filters.
schema:
$ref: '#/definitions/filterV1'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- read:filters
summary: Get all filters for the authenticated account.
tags:
- filters
post:
consumes:
- application/json
- application/xml
- application/x-www-form-urlencoded
operationId: filterV1Post
parameters:
- description: The text to be filtered.
example: fnord
in: formData
maxLength: 40
name: phrase
required: true
type: string
- description: The contexts in which the filter should be applied.
enum:
- home
- notifications
- public
- thread
- account
example:
- home
- public
in: formData
items:
$ref: '#/definitions/filterContext'
minLength: 1
name: context
required: true
type: array
uniqueItems: true
- description: Number of seconds from now that the filter should expire. If omitted, filter never expires.
example: 86400
in: formData
name: expires_in
type: number
- default: false
description: Should matching entities be removed from the user's timelines/views, instead of hidden? Not supported yet.
example: false
in: formData
name: irreversible
type: boolean
- default: false
description: Should the filter consider word boundaries?
example: true
in: formData
name: whole_word
type: boolean
produces:
- application/json
responses:
"200":
description: New filter.
schema:
$ref: '#/definitions/filterV1'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"422":
description: unprocessable content
"500":
description: internal server error
security:
- OAuth2 Bearer:
- write:filters
summary: Create a single filter.
tags:
- filters
/api/v1/filters/{id}:
delete:
operationId: filterV1Delete
parameters:
- description: ID of the list
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: filter deleted
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- write:filters
summary: Delete a single filter with the given ID.
tags:
- filters
get:
operationId: filterV1Get
parameters:
- description: ID of the filter
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: Requested filter.
schema:
$ref: '#/definitions/filterV1'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"500":
description: internal server error
security:
- OAuth2 Bearer:
- read:filters
summary: Get a single filter with the given ID.
tags:
- filters
put:
consumes:
- application/json
- application/xml
- application/x-www-form-urlencoded
operationId: filterV1Put
parameters:
- description: ID of the filter.
in: path
name: id
required: true
type: string
- description: The text to be filtered.
example: fnord
in: formData
maxLength: 40
name: phrase
required: true
type: string
- description: The contexts in which the filter should be applied.
enum:
- home
- notifications
- public
- thread
- account
example:
- home
- public
in: formData
items:
$ref: '#/definitions/filterContext'
minLength: 1
name: context
required: true
type: array
uniqueItems: true
- description: Number of seconds from now that the filter should expire. If omitted, filter never expires.
example: 86400
in: formData
name: expires_in
type: number
- default: false
description: Should matching entities be removed from the user's timelines/views, instead of hidden? Not supported yet.
example: false
in: formData
name: irreversible
type: boolean
- default: false
description: Should the filter consider word boundaries?
example: true
in: formData
name: whole_word
type: boolean
produces:
- application/json
responses:
"200":
description: Updated filter.
schema:
$ref: '#/definitions/filterV1'
"400":
description: bad request
"401":
description: unauthorized
"404":
description: not found
"406":
description: not acceptable
"422":
description: unprocessable content
"500":
description: internal server error
security:
- OAuth2 Bearer:
- write:filters
summary: Update a single filter with the given ID.
tags:
- filters
/api/v1/follow_requests:
get:
description: |-
Expand Down Expand Up @@ -7971,6 +8266,7 @@ securityDefinitions:
read:blocks: grant read access to blocks
read:custom_emojis: grant read access to custom_emojis
read:favourites: grant read access to favourites
read:filters: grant read access to filters
read:follows: grant read access to follows
read:lists: grant read access to lists
read:media: grant read access to media
Expand All @@ -7983,6 +8279,7 @@ securityDefinitions:
write: grants write access to everything
write:accounts: grants write access to accounts
write:blocks: grants write access to blocks
write:filters: grants write access to filters
write:follows: grants write access to follows
write:lists: grants write access to lists
write:media: grants write access to media
Expand Down
2 changes: 2 additions & 0 deletions docs/swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
// read:blocks: grant read access to blocks
// read:custom_emojis: grant read access to custom_emojis
// read:favourites: grant read access to favourites
// read:filters: grant read access to filters
// read:follows: grant read access to follows
// read:lists: grant read access to lists
// read:media: grant read access to media
Expand All @@ -48,6 +49,7 @@
// write: grants write access to everything
// write:accounts: grants write access to accounts
// write:blocks: grants write access to blocks
// write:filters: grants write access to filters
// write:follows: grants write access to follows
// write:lists: grants write access to lists
// write:media: grants write access to media
Expand Down
8 changes: 4 additions & 4 deletions internal/api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/api/client/customemojis"
"github.com/superseriousbusiness/gotosocial/internal/api/client/favourites"
"github.com/superseriousbusiness/gotosocial/internal/api/client/featuredtags"
filter "github.com/superseriousbusiness/gotosocial/internal/api/client/filters"
filtersV1 "github.com/superseriousbusiness/gotosocial/internal/api/client/filters/v1"
"github.com/superseriousbusiness/gotosocial/internal/api/client/followrequests"
"github.com/superseriousbusiness/gotosocial/internal/api/client/instance"
"github.com/superseriousbusiness/gotosocial/internal/api/client/lists"
Expand Down Expand Up @@ -62,7 +62,7 @@ type Client struct {
customEmojis *customemojis.Module // api/v1/custom_emojis
favourites *favourites.Module // api/v1/favourites
featuredTags *featuredtags.Module // api/v1/featured_tags
filters *filter.Module // api/v1/filters
filtersV1 *filtersV1.Module // api/v1/filters
followRequests *followrequests.Module // api/v1/follow_requests
instance *instance.Module // api/v1/instance
lists *lists.Module // api/v1/lists
Expand Down Expand Up @@ -104,7 +104,7 @@ func (c *Client) Route(r *router.Router, m ...gin.HandlerFunc) {
c.customEmojis.Route(h)
c.favourites.Route(h)
c.featuredTags.Route(h)
c.filters.Route(h)
c.filtersV1.Route(h)
c.followRequests.Route(h)
c.instance.Route(h)
c.lists.Route(h)
Expand Down Expand Up @@ -134,7 +134,7 @@ func NewClient(db db.DB, p *processing.Processor) *Client {
customEmojis: customemojis.New(p),
favourites: favourites.New(p),
featuredTags: featuredtags.New(p),
filters: filter.New(p),
filtersV1: filtersV1.New(p),
followRequests: followrequests.New(p),
instance: instance.New(p),
lists: lists.New(p),
Expand Down

0 comments on commit 61a2b91

Please sign in to comment.