From 8094955461419661b88a0361a5d7caed4b19c29a Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Mon, 16 Dec 2019 23:55:28 +0100 Subject: Add Event activity-type support (#12637) This adds support for Event AP type in Mastodon. Events are converted into toots by taking their title (AS name) and their URL (AP ID). Event picture is also brought in if available. Testable by fetching event content from https://test.mobilizon.org Signed-off-by: Thomas Citharel --- app/lib/activitypub/activity.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/lib') diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 0ca6b92a4..49b1dc9cd 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -5,7 +5,7 @@ class ActivityPub::Activity include Redisable SUPPORTED_TYPES = %w(Note Question).freeze - CONVERTED_TYPES = %w(Image Audio Video Article Page).freeze + CONVERTED_TYPES = %w(Image Audio Video Article Page Event).freeze def initialize(json, account, **options) @json = json -- cgit From da2143b3089ec16fca449b97acbfb65acfe92197 Mon Sep 17 00:00:00 2001 From: ThibG Date: Tue, 17 Dec 2019 13:31:56 +0100 Subject: Fixes featured hashtag setting page erroring out instead of rejecting invalid tags (#12436) * Revert "Fix ignoring whole status because of one invalid hashtag (#11621)" This reverts commit dff46b260b2f7d765d254c84a4b89105c7de5e97. * Fix statuses being rejected because of invalid hashtag names * Add spec for invalid hashtag names in statuses * Add test for featured tags controller --- app/lib/activitypub/activity/create.rb | 2 +- app/models/tag.rb | 2 +- .../settings/featured_tags_controller_spec.rb | 43 ++++++++++++++++++++++ spec/lib/activitypub/activity/create_spec.rb | 22 +++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 spec/controllers/settings/featured_tags_controller_spec.rb (limited to 'app/lib') diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 8a12a2b08..756d5cb1c 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -157,7 +157,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity return if tag['name'].blank? Tag.find_or_create_by_names(tag['name']) do |hashtag| - @tags << hashtag unless @tags.include?(hashtag) + @tags << hashtag unless @tags.include?(hashtag) || !hashtag.valid? end rescue ActiveRecord::RecordInvalid nil diff --git a/app/models/tag.rb b/app/models/tag.rb index d3a7e1e6d..bce76fc16 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -117,7 +117,7 @@ class Tag < ApplicationRecord class << self def find_or_create_by_names(name_or_names) Array(name_or_names).map(&method(:normalize)).uniq { |str| str.mb_chars.downcase.to_s }.map do |normalized_name| - tag = matching_name(normalized_name).first || create!(name: normalized_name) + tag = matching_name(normalized_name).first || create(name: normalized_name) yield tag if block_given? diff --git a/spec/controllers/settings/featured_tags_controller_spec.rb b/spec/controllers/settings/featured_tags_controller_spec.rb new file mode 100644 index 000000000..33b87f9f6 --- /dev/null +++ b/spec/controllers/settings/featured_tags_controller_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +describe Settings::FeaturedTagsController do + render_views + + shared_examples 'authenticate user' do + it 'redirects to sign_in page' do + is_expected.to redirect_to new_user_session_path + end + end + + describe 'POST #create' do + context 'when user is not sign in' do + subject { post :create } + + it_behaves_like 'authenticate user' + end + + context 'when user is sign in' do + subject { post :create, params: { featured_tag: params } } + + let(:user) { Fabricate(:user, password: '12345678') } + + before { sign_in user, scope: :user } + + context 'when parameter is valid' do + let(:params) { { name: 'test' } } + + it 'creates featured tag' do + expect { subject }.to change { user.account.featured_tags.count }.by(1) + end + end + + context 'when parameter is invalid' do + let(:params) { { name: 'test, #foo !bleh' } } + + it 'renders new' do + expect(subject).to render_template :index + end + end + end + end +end diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index b709954a3..c4efb5cc9 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -378,6 +378,28 @@ RSpec.describe ActivityPub::Activity::Create do end end + context 'with hashtags invalid name' do + let(:object_json) do + { + id: [ActivityPub::TagManager.instance.uri_for(sender), '#bar'].join, + type: 'Note', + content: 'Lorem ipsum', + tag: [ + { + type: 'Hashtag', + href: 'http://example.com/blah', + name: 'foo, #eh !', + }, + ], + } + end + + it 'creates status' do + status = sender.statuses.first + expect(status).to_not be_nil + end + end + context 'with emojis' do let(:object_json) do { -- cgit From 2ee5a9d9c319f187d4e94f6974654e1701e427eb Mon Sep 17 00:00:00 2001 From: ThibG Date: Tue, 17 Dec 2019 13:32:57 +0100 Subject: Clean up OStatus-related codepaths (#12173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove “protocol” argument and return value, as only ActivityPub is supported * Remove FetchRemoteAccountService, only use ActivityPub::FetchRemoteAccountService * Fix tests --- app/lib/activitypub/activity/create.rb | 2 +- app/services/fetch_remote_account_service.rb | 17 -------- app/services/fetch_remote_status_service.rb | 9 ++-- app/services/fetch_resource_service.rb | 2 +- app/services/resolve_url_service.rb | 10 ++--- spec/services/fetch_remote_account_service_spec.rb | 50 ---------------------- spec/services/fetch_remote_status_service_spec.rb | 7 ++- spec/services/fetch_resource_service_spec.rb | 8 ++-- 8 files changed, 15 insertions(+), 90 deletions(-) delete mode 100644 app/services/fetch_remote_account_service.rb delete mode 100644 spec/services/fetch_remote_account_service_spec.rb (limited to 'app/lib') diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index 756d5cb1c..c55cfe08e 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -167,7 +167,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity return if tag['href'].blank? account = account_from_uri(tag['href']) - account = ::FetchRemoteAccountService.new.call(tag['href']) if account.nil? + account = ActivityPub::FetchRemoteAccountService.new.call(tag['href']) if account.nil? return if account.nil? diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb deleted file mode 100644 index 3cd06e30f..000000000 --- a/app/services/fetch_remote_account_service.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -class FetchRemoteAccountService < BaseService - def call(url, prefetched_body = nil, protocol = :ostatus) - if prefetched_body.nil? - resource_url, resource_options, protocol = FetchResourceService.new.call(url) - else - resource_url = url - resource_options = { prefetched_body: prefetched_body } - end - - case protocol - when :activitypub - ActivityPub::FetchRemoteAccountService.new.call(resource_url, **resource_options) - end - end -end diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb index 208dc7809..21d277aff 100644 --- a/app/services/fetch_remote_status_service.rb +++ b/app/services/fetch_remote_status_service.rb @@ -1,17 +1,14 @@ # frozen_string_literal: true class FetchRemoteStatusService < BaseService - def call(url, prefetched_body = nil, protocol = :ostatus) + def call(url, prefetched_body = nil) if prefetched_body.nil? - resource_url, resource_options, protocol = FetchResourceService.new.call(url) + resource_url, resource_options = FetchResourceService.new.call(url) else resource_url = url resource_options = { prefetched_body: prefetched_body } end - case protocol - when :activitypub - ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options) - end + ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options) end end diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb index 3676d899d..34382d279 100644 --- a/app/services/fetch_resource_service.rb +++ b/app/services/fetch_resource_service.rb @@ -33,7 +33,7 @@ class FetchResourceService < BaseService body = response.body_with_limit json = body_to_json(body) - [json['id'], { prefetched_body: body, id: true }, :activitypub] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) || expected_type?(json)) + [json['id'], { prefetched_body: body, id: true }] if supported_context?(json) && (equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) || expected_type?(json)) elsif !terminal link_header = response['Link'] && parse_link_header(response) diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb index 4e971a4b8..79b1bad0c 100644 --- a/app/services/resolve_url_service.rb +++ b/app/services/resolve_url_service.rb @@ -19,9 +19,9 @@ class ResolveURLService < BaseService def process_url if equals_or_includes_any?(type, ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) - FetchRemoteAccountService.new.call(resource_url, body, protocol) + ActivityPub::FetchRemoteAccountService.new.call(resource_url, prefetched_body: body) elsif equals_or_includes_any?(type, ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES) - status = FetchRemoteStatusService.new.call(resource_url, body, protocol) + status = FetchRemoteStatusService.new.call(resource_url, body) authorize_with @on_behalf_of, status, :show? unless status.nil? status elsif fetched_resource.nil? && @on_behalf_of.present? @@ -45,12 +45,8 @@ class ResolveURLService < BaseService fetched_resource.second[:prefetched_body] end - def protocol - fetched_resource.third - end - def type - return json_data['type'] if protocol == :activitypub + json_data['type'] end def json_data diff --git a/spec/services/fetch_remote_account_service_spec.rb b/spec/services/fetch_remote_account_service_spec.rb deleted file mode 100644 index ee7325be2..000000000 --- a/spec/services/fetch_remote_account_service_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -require 'rails_helper' - -RSpec.describe FetchRemoteAccountService, type: :service do - let(:url) { 'https://example.com/alice' } - let(:prefetched_body) { nil } - let(:protocol) { :ostatus } - - subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) } - - let(:actor) do - { - '@context': 'https://www.w3.org/ns/activitystreams', - id: 'https://example.com/alice', - type: 'Person', - preferredUsername: 'alice', - name: 'Alice', - summary: 'Foo bar', - inbox: 'http://example.com/alice/inbox', - } - end - - let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } } - let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) } - - shared_examples 'return Account' do - it { is_expected.to be_an Account } - end - - context 'protocol is :activitypub' do - let(:prefetched_body) { Oj.dump(actor) } - let(:protocol) { :activitypub } - - before do - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - include_examples 'return Account' - end - - context 'when prefetched_body is nil' do - context 'protocol is :activitypub' do - before do - stub_request(:get, url).to_return(status: 200, body: Oj.dump(actor), headers: { 'Content-Type' => 'application/activity+json' }) - stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' }) - end - - include_examples 'return Account' - end - end -end diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb index f9db024b9..1c4b4fee2 100644 --- a/spec/services/fetch_remote_status_service_spec.rb +++ b/spec/services/fetch_remote_status_service_spec.rb @@ -16,9 +16,8 @@ RSpec.describe FetchRemoteStatusService, type: :service do end context 'protocol is :activitypub' do - subject { described_class.new.call(note[:id], prefetched_body, protocol) } + subject { described_class.new.call(note[:id], prefetched_body) } let(:prefetched_body) { Oj.dump(note) } - let(:protocol) { :activitypub } before do account.update(uri: ActivityPub::TagManager.instance.uri_for(account)) @@ -59,7 +58,7 @@ RSpec.describe FetchRemoteStatusService, type: :service do XML - expect(subject.call('https://fake.domain/foo', status_body, :ostatus)).to be_nil + expect(subject.call('https://fake.domain/foo', status_body)).to be_nil end it 'does not create status with wrong id when id uses http format' do @@ -81,7 +80,7 @@ RSpec.describe FetchRemoteStatusService, type: :service do XML - expect(subject.call('https://real.domain/statuses/456', status_body, :ostatus)).to be_nil + expect(subject.call('https://real.domain/statuses/456', status_body)).to be_nil end end end diff --git a/spec/services/fetch_resource_service_spec.rb b/spec/services/fetch_resource_service_spec.rb index f836147d3..3af6a0689 100644 --- a/spec/services/fetch_resource_service_spec.rb +++ b/spec/services/fetch_resource_service_spec.rb @@ -71,14 +71,14 @@ RSpec.describe FetchResourceService, type: :service do let(:content_type) { 'application/activity+json; charset=utf-8' } let(:body) { json } - it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] } + it { is_expected.to eq [1, { prefetched_body: body, id: true }] } end context 'when content type is ld+json with profile' do let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' } let(:body) { json } - it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] } + it { is_expected.to eq [1, { prefetched_body: body, id: true }] } end before do @@ -89,14 +89,14 @@ RSpec.describe FetchResourceService, type: :service do context 'when link header is present' do let(:headers) { { 'Link' => '; rel="alternate"; type="application/activity+json"', } } - it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] } + it { is_expected.to eq [1, { prefetched_body: json, id: true }] } end context 'when content type is text/html' do let(:content_type) { 'text/html' } let(:body) { '' } - it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] } + it { is_expected.to eq [1, { prefetched_body: json, id: true }] } end end end -- cgit