Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

他サーバーからカスタム絵文字によるスタンプを受け取った時に、ライセンス情報を保存する+ついでにテスト #65

Merged
merged 9 commits into from
Oct 7, 2023
Merged
58 changes: 45 additions & 13 deletions app/lib/activitypub/activity/like.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
def perform
@original_status = status_from_uri(object_uri)

return if @original_status.nil? || delete_arrived_first?(@json['id']) || reject_favourite?
return if @original_status.nil? || delete_arrived_first?(@json['id']) || block_domain? || reject_favourite?

if shortcode.nil? || !Setting.enable_emoji_reaction
process_favourite
Expand All @@ -34,19 +34,11 @@ def process_favourite
def process_emoji_reaction
return if !@original_status.account.local? && !Setting.receive_other_servers_emoji_reaction

# custom emoji
emoji = nil
if emoji_tag.present?
return if emoji_tag['id'].blank? || emoji_tag['name'].blank? || emoji_tag['icon'].blank? || emoji_tag['icon']['url'].blank?

image_url = emoji_tag['icon']['url']
uri = emoji_tag['id']
domain = URI.split(uri)[2]

emoji = CustomEmoji.find_or_create_by!(shortcode: shortcode, domain: domain) do |emoji_data|
emoji_data.uri = uri
emoji_data.image_remote_url = image_url
end

Trends.statuses.register(@original_status)
emoji = process_emoji(emoji_tag)
return if emoji.nil?
end

reaction = nil
Expand All @@ -58,6 +50,7 @@ def process_emoji_reaction
reaction = @original_status.emoji_reactions.create!(account: @account, name: shortcode, custom_emoji: emoji, uri: @json['id'])
end

Trends.statuses.register(@original_status)
write_stream(reaction)

if @original_status.account.local?
Expand Down Expand Up @@ -95,6 +88,45 @@ def shortcode
end
end

def process_emoji(tag)
custom_emoji_parser = ActivityPub::Parser::CustomEmojiParser.new(tag)

return if custom_emoji_parser.shortcode.blank? || custom_emoji_parser.image_remote_url.blank?

emoji = CustomEmoji.find_by(shortcode: custom_emoji_parser.shortcode, domain: @account.domain)

return unless emoji.nil? || custom_emoji_parser.image_remote_url != emoji.image_remote_url || (custom_emoji_parser.updated_at && custom_emoji_parser.updated_at >= emoji.updated_at)

domain = emoji_tag['domain'] || URI.split(custom_emoji_parser.uri)[2] || @account.domain
domain = nil if domain == Rails.configuration.x.local_domain || domain == Rails.configuration.x.web_domain

return if domain.present? && skip_download?(domain)

begin
emoji ||= CustomEmoji.new(
domain: domain,
shortcode: custom_emoji_parser.shortcode,
uri: custom_emoji_parser.uri,
is_sensitive: custom_emoji_parser.is_sensitive,
license: custom_emoji_parser.license
)
emoji.image_remote_url = custom_emoji_parser.image_remote_url
emoji.save
rescue Seahorse::Client::NetworkingError => e
Rails.logger.warn "Error storing emoji: #{e}"
end

emoji
end

def skip_download?(domain)
DomainBlock.reject_media?(domain)
end

def block_domain?
DomainBlock.blocked?(@account.domain)
end

def misskey_favourite?
misskey_shortcode = @json['_misskey_reaction']&.delete(':')

Expand Down
2 changes: 1 addition & 1 deletion app/lib/activitypub/parser/custom_emoji_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ def is_sensitive # rubocop:disable Naming/PredicateName
end

def license
@json['license']
@json['license'] || @json['licence']
end
end
8 changes: 7 additions & 1 deletion app/serializers/activitypub/emoji_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ class ActivityPub::EmojiSerializer < ActivityPub::Serializer

context_extensions :emoji

attributes :id, :type, :name, :updated
attributes :id, :type, :domain, :name, :is_sensitive, :updated

attribute :license, if: -> { object.license.present? }

has_one :icon, serializer: ActivityPub::ImageSerializer

Expand All @@ -17,6 +19,10 @@ def type
'Emoji'
end

def domain
object.domain.presence || Rails.configuration.x.local_domain
end

def icon
object.image
end
Expand Down
221 changes: 220 additions & 1 deletion spec/lib/activitypub/activity/like_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,225 @@
end
end

describe '#perform when receive emoji reaction' do
subject do
described_class.new(json, sender).perform
EmojiReaction.where(status: status)
end

before do
stub_request(:get, 'http://example.com/emoji.png').to_return(body: attachment_fixture('emojo.png'))
end

let(:json) do
{
'@context': 'https://www.w3.org/ns/activitystreams',
id: 'foo',
type: 'Like',
actor: ActivityPub::TagManager.instance.uri_for(sender),
object: ActivityPub::TagManager.instance.uri_for(status),
content: content,
tag: tag,
}.with_indifferent_access
end
let(:content) { nil }
let(:tag) { nil }

context 'with unicode emoji' do
let(:content) { '😀' }

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq '😀'
expect(subject.first.account).to eq sender
expect(sender.favourited?(status)).to be false
end
end

context 'with custom emoji' do
let(:content) { ':tinking:' }
let(:tag) do
{
id: 'https://example.com/aaa',
type: 'Emoji',
icon: {
url: 'http://example.com/emoji.png',
},
name: 'tinking',
license: 'Everyone but Ohagi',
}
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq 'tinking'
expect(subject.first.account).to eq sender
expect(subject.first.custom_emoji).to_not be_nil
expect(subject.first.custom_emoji.shortcode).to eq 'tinking'
expect(subject.first.custom_emoji.domain).to eq 'example.com'
expect(sender.favourited?(status)).to be false
end

it 'custom emoji license is saved' do
expect(subject.first.custom_emoji.license).to eq 'Everyone but Ohagi'
end
end

context 'with custom emoji and custom domain' do
let(:content) { ':tinking:' }
let(:tag) do
{
id: 'https://example.com/aaa',
type: 'Emoji',
domain: 'post.kmycode.net',
icon: {
url: 'http://example.com/emoji.png',
},
name: 'tinking',
}
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq 'tinking'
expect(subject.first.account).to eq sender
expect(subject.first.custom_emoji).to_not be_nil
expect(subject.first.custom_emoji.shortcode).to eq 'tinking'
expect(subject.first.custom_emoji.domain).to eq 'post.kmycode.net'
expect(sender.favourited?(status)).to be false
end
end

context 'with custom emoji but invalid id' do
let(:content) { ':tinking:' }
let(:tag) do
{
id: 'aaa',
type: 'Emoji',
icon: {
url: 'http://example.com/emoji.png',
},
name: 'tinking',
}
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq 'tinking'
expect(subject.first.account).to eq sender
expect(subject.first.custom_emoji).to_not be_nil
expect(subject.first.custom_emoji.shortcode).to eq 'tinking'
expect(subject.first.custom_emoji.domain).to eq 'example.com'
expect(sender.favourited?(status)).to be false
end
end

context 'with custom emoji but local domain' do
let(:content) { ':tinking:' }
let(:tag) do
{
id: 'aaa',
type: 'Emoji',
domain: Rails.configuration.x.local_domain,
icon: {
url: 'http://example.com/emoji.png',
},
name: 'tinking',
}
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq 'tinking'
expect(subject.first.account).to eq sender
expect(subject.first.custom_emoji).to_not be_nil
expect(subject.first.custom_emoji.shortcode).to eq 'tinking'
expect(subject.first.custom_emoji.domain).to be_nil
expect(sender.favourited?(status)).to be false
end
end

context 'with unicode emoji and reject_media enabled' do
let(:content) { '😀' }

before do
Fabricate(:domain_block, domain: 'example.com', severity: :noop, reject_media: true)
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq '😀'
expect(subject.first.account).to eq sender
expect(sender.favourited?(status)).to be false
end
end

context 'with custom emoji and reject_media enabled' do
let(:content) { ':tinking:' }
let(:tag) do
{
id: 'https://example.com/aaa',
type: 'Emoji',
icon: {
url: 'http://example.com/emoji.png',
},
name: 'tinking',
}
end

before do
Fabricate(:domain_block, domain: 'example.com', severity: :noop, reject_media: true)
end

it 'create emoji reaction' do
expect(subject.count).to eq 0
expect(sender.favourited?(status)).to be false
end
end

context 'when emoji reaction is disabled' do
let(:content) { '😀' }

before do
Form::AdminSettings.new(enable_emoji_reaction: false).save
end

it 'create emoji reaction' do
expect(subject.count).to eq 0
expect(sender.favourited?(status)).to be true
end
end

context 'when emoji reaction between other servers is disabled' do
let(:recipient) { Fabricate(:account, domain: 'narrow.com', uri: 'https://narrow.com/') }
let(:content) { '😀' }

before do
Form::AdminSettings.new(receive_other_servers_emoji_reaction: false).save
end

it 'create emoji reaction' do
expect(subject.count).to eq 0
expect(sender.favourited?(status)).to be false
end
end

context 'when emoji reaction between other servers is disabled but that status is local' do
let(:content) { '😀' }

before do
Form::AdminSettings.new(receive_other_servers_emoji_reaction: false).save
end

it 'create emoji reaction' do
expect(subject.count).to eq 1
expect(subject.first.name).to eq '😀'
expect(subject.first.account).to eq sender
expect(sender.favourited?(status)).to be false
end
end
end

describe '#perform when domain_block' do
subject { described_class.new(json, sender) }

Expand All @@ -50,7 +269,7 @@
subject.perform
end

it 'does not create a favourite from sender to status', pending: 'considering spec' do
it 'does not create a favourite from sender to status' do
expect(sender.favourited?(status)).to be false
end
end
Expand Down