Skip to content

Commit

Permalink
Fix validation error in SynchronizeFeaturedTagsCollectionWorker (mast…
Browse files Browse the repository at this point in the history
…odon#20018)

* Fix followers count not being updated when migrating follows

Fixes mastodon#19900

* Fix validation error in SynchronizeFeaturedTagsCollectionWorker

Also saves remote user's chosen case for hashtags

* Limit remote featured tags before validation
  • Loading branch information
ClearlyClaire authored Nov 7, 2022
1 parent 3114c82 commit bbf7449
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 13 deletions.
2 changes: 2 additions & 0 deletions app/models/featured_tag.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def reset_data
end

def validate_featured_tags_limit
return unless account.local?

errors.add(:base, I18n.t('featured_tags.errors.limit')) if account.featured_tags.count >= LIMIT
end

Expand Down
22 changes: 9 additions & 13 deletions app/services/activitypub/fetch_featured_tags_collection_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,17 @@ def fetch_collection(collection_or_uri)
end

def process_items(items)
names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.map { |name| HashtagNormalizer.new.normalize(name) }
to_remove = []
to_add = names

FeaturedTag.where(account: @account).map(&:name).each do |name|
if names.include?(name)
to_add.delete(name)
else
to_remove << name
end
end
names = items.filter_map { |item| item['type'] == 'Hashtag' && item['name']&.delete_prefix('#') }.take(FeaturedTag::LIMIT)
tags = names.index_by { |name| HashtagNormalizer.new.normalize(name) }
normalized_names = tags.keys

FeaturedTag.includes(:tag).where(account: @account, tags: { name: to_remove }).delete_all unless to_remove.empty?
FeaturedTag.includes(:tag).references(:tag).where(account: @account).where.not(tag: { name: normalized_names }).delete_all

FeaturedTag.includes(:tag).references(:tag).where(account: @account, tag: { name: normalized_names }).each do |featured_tag|
featured_tag.update(name: tags.delete(featured_tag.tag.name))
end

to_add.each do |name|
tags.each_value do |name|
FeaturedTag.create!(account: @account, name: name)
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require 'rails_helper'

RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service do
let(:collection_url) { 'https://example.com/account/tags' }
let(:actor) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/account') }

let(:items) do
[
{ type: 'Hashtag', href: 'https://example.com/account/tagged/foo', name: 'Foo' },
{ type: 'Hashtag', href: 'https://example.com/account/tagged/bar', name: 'bar' },
{ type: 'Hashtag', href: 'https://example.com/account/tagged/baz', name: 'baZ' },
]
end

let(:payload) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
type: 'Collection',
id: collection_url,
items: items,
}.with_indifferent_access
end

subject { described_class.new }

shared_examples 'sets featured tags' do
before do
subject.call(actor, collection_url)
end

it 'sets expected tags as pinned tags' do
expect(actor.featured_tags.map(&:display_name)).to match_array ['Foo', 'bar', 'baZ']
end
end

describe '#call' do
context 'when the endpoint is a Collection' do
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
end

it_behaves_like 'sets featured tags'
end

context 'when the account already has featured tags' do
before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))

actor.featured_tags.create!(name: 'FoO')
actor.featured_tags.create!(name: 'baz')
actor.featured_tags.create!(name: 'oh').update(name: nil)
end

it_behaves_like 'sets featured tags'
end

context 'when the endpoint is an OrderedCollection' do
let(:payload) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
type: 'OrderedCollection',
id: collection_url,
orderedItems: items,
}.with_indifferent_access
end

before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
end

it_behaves_like 'sets featured tags'
end

context 'when the endpoint is a paginated Collection' do
let(:payload) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
type: 'Collection',
id: collection_url,
first: {
type: 'CollectionPage',
partOf: collection_url,
items: items,
}
}.with_indifferent_access
end

before do
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
end

it_behaves_like 'sets featured tags'
end
end
end

0 comments on commit bbf7449

Please sign in to comment.