2022-06-01 17:09:37 +00:00
# frozen_string_literal: true
require 'rails_helper'
RSpec . describe StatusRelationshipsPresenter do
describe '.initialize' do
before do
Revamp post filtering system (#18058)
* Add model for custom filter keywords
* Use CustomFilterKeyword internally
Does not change the API
* Fix /filters/edit and /filters/new
* Add migration tests
* Remove whole_word column from custom_filters (covered by custom_filter_keywords)
* Redesign /filters
Instead of a list, present a card that displays more information and handles
multiple keywords per filter.
* Redesign /filters/new and /filters/edit to add and remove keywords
This adds a new gem dependency: cocoon, as well as a npm dependency:
cocoon-js-vanilla. Those are used to easily populate and remove form fields
from the user interface when manipulating multiple keyword filters at once.
* Add /api/v2/filters to edit filter with multiple keywords
Entities:
- `Filter`: `id`, `title`, `filter_action` (either `hide` or `warn`), `context`
`keywords`
- `FilterKeyword`: `id`, `keyword`, `whole_word`
API endpoits:
- `GET /api/v2/filters` to list filters (including keywords)
- `POST /api/v2/filters` to create a new filter
`keywords_attributes` can also be passed to create keywords in one request
- `GET /api/v2/filters/:id` to read a particular filter
- `PUT /api/v2/filters/:id` to update a new filter
`keywords_attributes` can also be passed to edit, delete or add keywords in
one request
- `DELETE /api/v2/filters/:id` to delete a particular filter
- `GET /api/v2/filters/:id/keywords` to list keywords for a filter
- `POST /api/v2/filters/:filter_id/keywords/:id` to add a new keyword to a
filter
- `GET /api/v2/filter_keywords/:id` to read a particular keyword
- `PUT /api/v2/filter_keywords/:id` to edit a particular keyword
- `DELETE /api/v2/filter_keywords/:id` to delete a particular keyword
* Change from `irreversible` boolean to `action` enum
* Remove irrelevent `irreversible_must_be_within_context` check
* Fix /filters/new and /filters/edit with update for filter_action
* Fix Rubocop/Codeclimate complaining about task names
* Refactor FeedManager#phrase_filtered?
This moves regexp building and filter caching to the `CustomFilter` class.
This does not change the functional behavior yet, but this changes how the
cache is built, doing per-custom_filter regexps so that filters can be matched
independently, while still offering caching.
* Perform server-side filtering and output result in REST API
* Fix numerous filters_changed events being sent when editing multiple keywords at once
* Add some tests
* Use the new API in the WebUI
- use client-side logic for filters we have fetched rules for.
This is so that filter changes can be retroactively applied without
reloading the UI.
- use server-side logic for filters we haven't fetched rules for yet
(e.g. network error, or initial timeline loading)
* Minor optimizations and refactoring
* Perform server-side filtering on the streaming server
* Change the wording of filter action labels
* Fix issues pointed out by linter
* Change design of “Show anyway” link in accordence to review comments
* Drop “irreversible” filtering behavior
* Move /api/v2/filter_keywords to /api/v1/filters/keywords
* Rename `filter_results` attribute to `filtered`
* Rename REST::LegacyFilterSerializer to REST::V1::FilterSerializer
* Fix systemChannelId value in streaming server
* Simplify code by removing client-side filtering code
The simplifcation comes at a cost though: filters aren't retroactively
applied anymore.
2022-06-28 07:42:13 +00:00
allow ( Status ) . to receive ( :reblogs_map ) . with ( match_array ( status_ids ) , current_account_id ) . and_return ( default_map )
2022-06-01 17:09:37 +00:00
allow ( Status ) . to receive ( :favourites_map ) . with ( status_ids , current_account_id ) . and_return ( default_map )
allow ( Status ) . to receive ( :bookmarks_map ) . with ( status_ids , current_account_id ) . and_return ( default_map )
allow ( Status ) . to receive ( :mutes_map ) . with ( anything , current_account_id ) . and_return ( default_map )
allow ( Status ) . to receive ( :pins_map ) . with ( anything , current_account_id ) . and_return ( default_map )
end
2023-06-06 11:58:33 +00:00
let ( :presenter ) { described_class . new ( statuses , current_account_id , ** options ) }
2022-06-01 17:09:37 +00:00
let ( :current_account_id ) { Fabricate ( :account ) . id }
let ( :statuses ) { [ Fabricate ( :status ) ] }
2023-05-23 08:49:12 +00:00
let ( :status_ids ) { statuses . map ( & :id ) + statuses . filter_map ( & :reblog_of_id ) }
2022-06-01 17:09:37 +00:00
let ( :default_map ) { { 1 = > true } }
2023-05-04 03:49:08 +00:00
context 'when options are not set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { } }
it 'sets default maps' do
expect ( presenter . reblogs_map ) . to eq default_map
expect ( presenter . favourites_map ) . to eq default_map
expect ( presenter . bookmarks_map ) . to eq default_map
expect ( presenter . mutes_map ) . to eq default_map
expect ( presenter . pins_map ) . to eq default_map
end
end
2023-05-04 03:49:08 +00:00
context 'when options[:reblogs_map] is set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { reblogs_map : { 2 = > true } } }
it 'sets @reblogs_map merged with default_map and options[:reblogs_map]' do
expect ( presenter . reblogs_map ) . to eq default_map . merge ( options [ :reblogs_map ] )
end
end
2023-05-04 03:49:08 +00:00
context 'when options[:favourites_map] is set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { favourites_map : { 3 = > true } } }
it 'sets @favourites_map merged with default_map and options[:favourites_map]' do
expect ( presenter . favourites_map ) . to eq default_map . merge ( options [ :favourites_map ] )
end
end
2023-05-04 03:49:08 +00:00
context 'when options[:bookmarks_map] is set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { bookmarks_map : { 4 = > true } } }
it 'sets @bookmarks_map merged with default_map and options[:bookmarks_map]' do
expect ( presenter . bookmarks_map ) . to eq default_map . merge ( options [ :bookmarks_map ] )
end
end
2023-05-04 03:49:08 +00:00
context 'when options[:mutes_map] is set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { mutes_map : { 5 = > true } } }
it 'sets @mutes_map merged with default_map and options[:mutes_map]' do
expect ( presenter . mutes_map ) . to eq default_map . merge ( options [ :mutes_map ] )
end
end
2023-05-04 03:49:08 +00:00
context 'when options[:pins_map] is set' do
2022-06-01 17:09:37 +00:00
let ( :options ) { { pins_map : { 6 = > true } } }
it 'sets @pins_map merged with default_map and options[:pins_map]' do
expect ( presenter . pins_map ) . to eq default_map . merge ( options [ :pins_map ] )
end
end
Revamp post filtering system (#18058)
* Add model for custom filter keywords
* Use CustomFilterKeyword internally
Does not change the API
* Fix /filters/edit and /filters/new
* Add migration tests
* Remove whole_word column from custom_filters (covered by custom_filter_keywords)
* Redesign /filters
Instead of a list, present a card that displays more information and handles
multiple keywords per filter.
* Redesign /filters/new and /filters/edit to add and remove keywords
This adds a new gem dependency: cocoon, as well as a npm dependency:
cocoon-js-vanilla. Those are used to easily populate and remove form fields
from the user interface when manipulating multiple keyword filters at once.
* Add /api/v2/filters to edit filter with multiple keywords
Entities:
- `Filter`: `id`, `title`, `filter_action` (either `hide` or `warn`), `context`
`keywords`
- `FilterKeyword`: `id`, `keyword`, `whole_word`
API endpoits:
- `GET /api/v2/filters` to list filters (including keywords)
- `POST /api/v2/filters` to create a new filter
`keywords_attributes` can also be passed to create keywords in one request
- `GET /api/v2/filters/:id` to read a particular filter
- `PUT /api/v2/filters/:id` to update a new filter
`keywords_attributes` can also be passed to edit, delete or add keywords in
one request
- `DELETE /api/v2/filters/:id` to delete a particular filter
- `GET /api/v2/filters/:id/keywords` to list keywords for a filter
- `POST /api/v2/filters/:filter_id/keywords/:id` to add a new keyword to a
filter
- `GET /api/v2/filter_keywords/:id` to read a particular keyword
- `PUT /api/v2/filter_keywords/:id` to edit a particular keyword
- `DELETE /api/v2/filter_keywords/:id` to delete a particular keyword
* Change from `irreversible` boolean to `action` enum
* Remove irrelevent `irreversible_must_be_within_context` check
* Fix /filters/new and /filters/edit with update for filter_action
* Fix Rubocop/Codeclimate complaining about task names
* Refactor FeedManager#phrase_filtered?
This moves regexp building and filter caching to the `CustomFilter` class.
This does not change the functional behavior yet, but this changes how the
cache is built, doing per-custom_filter regexps so that filters can be matched
independently, while still offering caching.
* Perform server-side filtering and output result in REST API
* Fix numerous filters_changed events being sent when editing multiple keywords at once
* Add some tests
* Use the new API in the WebUI
- use client-side logic for filters we have fetched rules for.
This is so that filter changes can be retroactively applied without
reloading the UI.
- use server-side logic for filters we haven't fetched rules for yet
(e.g. network error, or initial timeline loading)
* Minor optimizations and refactoring
* Perform server-side filtering on the streaming server
* Change the wording of filter action labels
* Fix issues pointed out by linter
* Change design of “Show anyway” link in accordence to review comments
* Drop “irreversible” filtering behavior
* Move /api/v2/filter_keywords to /api/v1/filters/keywords
* Rename `filter_results` attribute to `filtered`
* Rename REST::LegacyFilterSerializer to REST::V1::FilterSerializer
* Fix systemChannelId value in streaming server
* Simplify code by removing client-side filtering code
The simplifcation comes at a cost though: filters aren't retroactively
applied anymore.
2022-06-28 07:42:13 +00:00
context 'when post includes filtered terms' do
let ( :statuses ) { [ Fabricate ( :status , text : 'this toot is about that banned word' ) , Fabricate ( :status , reblog : Fabricate ( :status , text : 'this toot is about an irrelevant word' ) ) ] }
let ( :options ) { { } }
before do
Account . find ( current_account_id ) . custom_filters . create! ( phrase : 'filter1' , context : %w( home ) , action : :hide , keywords_attributes : [ { keyword : 'banned' } , { keyword : 'irrelevant' } ] )
end
it 'sets @filters_map to filter top-level status' do
matched_filters = presenter . filters_map [ statuses [ 0 ] . id ]
expect ( matched_filters . size ) . to eq 1
expect ( matched_filters [ 0 ] . filter . title ) . to eq 'filter1'
expect ( matched_filters [ 0 ] . keyword_matches ) . to eq [ 'banned' ]
end
it 'sets @filters_map to filter reblogged status' do
matched_filters = presenter . filters_map [ statuses [ 1 ] . reblog_of_id ]
expect ( matched_filters . size ) . to eq 1
expect ( matched_filters [ 0 ] . filter . title ) . to eq 'filter1'
expect ( matched_filters [ 0 ] . keyword_matches ) . to eq [ 'irrelevant' ]
end
end
2022-08-25 02:27:47 +00:00
context 'when post includes filtered individual statuses' do
let ( :statuses ) { [ Fabricate ( :status , text : 'hello world' ) , Fabricate ( :status , reblog : Fabricate ( :status , text : 'this toot is about an irrelevant word' ) ) ] }
let ( :options ) { { } }
before do
filter = Account . find ( current_account_id ) . custom_filters . create! ( phrase : 'filter1' , context : %w( home ) , action : :hide )
filter . statuses . create! ( status_id : statuses [ 0 ] . id )
filter . statuses . create! ( status_id : statuses [ 1 ] . reblog_of_id )
end
it 'sets @filters_map to filter top-level status' do
matched_filters = presenter . filters_map [ statuses [ 0 ] . id ]
expect ( matched_filters . size ) . to eq 1
expect ( matched_filters [ 0 ] . filter . title ) . to eq 'filter1'
expect ( matched_filters [ 0 ] . status_matches ) . to eq [ statuses [ 0 ] . id ]
end
it 'sets @filters_map to filter reblogged status' do
matched_filters = presenter . filters_map [ statuses [ 1 ] . reblog_of_id ]
expect ( matched_filters . size ) . to eq 1
expect ( matched_filters [ 0 ] . filter . title ) . to eq 'filter1'
expect ( matched_filters [ 0 ] . status_matches ) . to eq [ statuses [ 1 ] . reblog_of_id ]
end
end
2022-06-01 17:09:37 +00:00
end
end