Merge branch 'master' into glitch-soc/merge-upstream

Conflicts:
- Gemfile.lock
- app/controllers/accounts_controller.rb
- app/controllers/admin/dashboard_controller.rb
- app/controllers/follower_accounts_controller.rb
- app/controllers/following_accounts_controller.rb
- app/controllers/remote_follow_controller.rb
- app/controllers/stream_entries_controller.rb
- app/controllers/tags_controller.rb
- app/javascript/packs/public.js
- app/lib/sanitize_config.rb
- app/models/account.rb
- app/models/form/admin_settings.rb
- app/models/media_attachment.rb
- app/models/stream_entry.rb
- app/models/user.rb
- app/serializers/initial_state_serializer.rb
- app/services/batched_remove_status_service.rb
- app/services/post_status_service.rb
- app/services/process_mentions_service.rb
- app/services/reblog_service.rb
- app/services/remove_status_service.rb
- app/views/admin/settings/edit.html.haml
- config/locales/simple_form.pl.yml
- config/settings.yml
- docker-compose.yml
This commit is contained in:
Thibaut Girka
2019-07-19 18:26:49 +02:00
411 changed files with 3416 additions and 8150 deletions

View File

@ -48,37 +48,6 @@ RSpec.describe AccountsController, type: :controller do
end
end
context 'atom' do
let(:format) { 'atom' }
let(:content_type) { 'application/atom+xml' }
shared_examples 'responsed streams' do
it 'assigns @entries' do
entries = assigns(:entries).to_a
expect(entries.size).to eq expected_statuses.size
entries.each.zip(expected_statuses.each) do |entry, expected_status|
expect(entry.status).to eq expected_status
end
end
end
include_examples 'responses'
context 'without max_id nor since_id' do
let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }
include_examples 'responsed streams'
end
context 'with max_id and since_id' do
let(:max_id) { status4.stream_entry.id }
let(:since_id) { status1.stream_entry.id }
let(:expected_statuses) { [status3, status2] }
include_examples 'responsed streams'
end
end
context 'activitystreams2' do
let(:format) { 'json' }
let(:content_type) { 'application/activity+json' }

View File

@ -4,7 +4,7 @@ require 'rails_helper'
RSpec.describe ActivityPub::InboxesController, type: :controller do
describe 'POST #create' do
context 'if signed_request_account' do
context 'with signed_request_account' do
it 'returns 202' do
allow(controller).to receive(:signed_request_account) do
Fabricate(:account)
@ -15,7 +15,7 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
end
end
context 'not signed_request_account' do
context 'without signed_request_account' do
it 'returns 401' do
allow(controller).to receive(:signed_request_account) do
false

View File

@ -75,44 +75,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
end
end
describe 'POST #subscribe' do
subject { post :subscribe, params: { id: account.id } }
let(:current_user) { Fabricate(:user, admin: admin) }
let(:account) { Fabricate(:account) }
context 'when user is admin' do
let(:admin) { true }
it { is_expected.to redirect_to admin_account_path(account.id) }
end
context 'when user is not admin' do
let(:admin) { false }
it { is_expected.to have_http_status :forbidden }
end
end
describe 'POST #unsubscribe' do
subject { post :unsubscribe, params: { id: account.id } }
let(:current_user) { Fabricate(:user, admin: admin) }
let(:account) { Fabricate(:account) }
context 'when user is admin' do
let(:admin) { true }
it { is_expected.to redirect_to admin_account_path(account.id) }
end
context 'when user is not admin' do
let(:admin) { false }
it { is_expected.to have_http_status :forbidden }
end
end
describe 'POST #memorialize' do
subject { post :memorialize, params: { id: account.id } }

View File

@ -1,32 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Admin::SubscriptionsController, type: :controller do
render_views
describe 'GET #index' do
around do |example|
default_per_page = Subscription.default_per_page
Subscription.paginates_per 1
example.run
Subscription.paginates_per default_per_page
end
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
it 'renders subscriptions' do
Fabricate(:subscription)
specified = Fabricate(:subscription)
get :index
subscriptions = assigns(:subscriptions)
expect(subscriptions.count).to eq 1
expect(subscriptions[0]).to eq specified
expect(response).to have_http_status(200)
end
end
end

View File

@ -9,7 +9,7 @@ RSpec.describe Api::OEmbedController, type: :controller do
describe 'GET #show' do
before do
request.host = Rails.configuration.x.local_domain
get :show, params: { url: account_stream_entry_url(alice, status.stream_entry) }, format: :json
get :show, params: { url: short_account_status_url(alice, status) }, format: :json
end
it 'returns http success' do

View File

@ -1,59 +0,0 @@
require 'rails_helper'
RSpec.describe Api::PushController, type: :controller do
describe 'POST #update' do
context 'with hub.mode=subscribe' do
it 'creates a subscription' do
service = double(call: ['', 202])
allow(Pubsubhubbub::SubscribeService).to receive(:new).and_return(service)
account = Fabricate(:account)
account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
post :update, params: {
'hub.mode' => 'subscribe',
'hub.topic' => account_topic_url,
'hub.callback' => 'https://callback.host/api',
'hub.lease_seconds' => '3600',
'hub.secret' => 'as1234df',
}
expect(service).to have_received(:call).with(
account,
'https://callback.host/api',
'as1234df',
'3600',
nil
)
expect(response).to have_http_status(202)
end
end
context 'with hub.mode=unsubscribe' do
it 'unsubscribes the account' do
service = double(call: ['', 202])
allow(Pubsubhubbub::UnsubscribeService).to receive(:new).and_return(service)
account = Fabricate(:account)
account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
post :update, params: {
'hub.mode' => 'unsubscribe',
'hub.topic' => account_topic_url,
'hub.callback' => 'https://callback.host/api',
}
expect(service).to have_received(:call).with(
account,
'https://callback.host/api',
)
expect(response).to have_http_status(202)
end
end
context 'with unknown mode' do
it 'returns an unknown mode error' do
post :update, params: { 'hub.mode' => 'fake' }
expect(response).to have_http_status(422)
expect(response.body).to match(/Unknown mode/)
end
end
end
end

View File

@ -1,65 +0,0 @@
require 'rails_helper'
RSpec.describe Api::SalmonController, type: :controller do
render_views
let(:account) { Fabricate(:user, account: Fabricate(:account, username: 'catsrgr8')).account }
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
end
describe 'POST #update' do
context 'with valid post data' do
before do
post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
end
it 'contains XML in the request body' do
expect(request.body.read).to be_a String
end
it 'returns http success' do
expect(response).to have_http_status(202)
end
it 'creates remote account' do
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
end
it 'creates status' do
expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil
end
it 'creates mention for target account' do
expect(account.mentions.count).to eq 1
end
end
context 'with empty post data' do
before do
post :update, params: { id: account.id }, body: ''
end
it 'returns http client error' do
expect(response).to have_http_status(400)
end
end
context 'with invalid post data' do
before do
service = double(call: false)
allow(VerifySalmonService).to receive(:new).and_return(service)
post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
end
it 'returns http client error' do
expect(response).to have_http_status(401)
end
end
end
end

View File

@ -1,68 +0,0 @@
require 'rails_helper'
RSpec.describe Api::SubscriptionsController, type: :controller do
render_views
let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') }
describe 'GET #show' do
context 'with valid subscription' do
before do
get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'echoes back the challenge' do
expect(response.body).to match '456'
end
end
context 'with invalid subscription' do
before do
expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false)
get :show, params: { :id => account.id }
end
it 'returns http success' do
expect(response).to have_http_status(404)
end
end
end
describe 'POST #update' do
let(:feed) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
before do
stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
stub_request(:get, "https://quitter.no/notice/1269244").to_return(status: 404)
stub_request(:get, "https://quitter.no/notice/1265331").to_return(status: 404)
stub_request(:get, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
stub_request(:get, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
stub_request(:get, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
stub_request(:get, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
stub_request(:get, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
stub_request(:get, "https://quitter.no/notice/1243309").to_return(status: 404)
stub_request(:get, "https://quitter.no/user/7477").to_return(status: 404)
stub_request(:any, "https://community.highlandarrow.com/user/1").to_return(status: 404)
stub_request(:any, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
stub_request(:any, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404)
request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
post :update, params: { id: account.id }, body: feed
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'creates statuses for feed' do
expect(account.statuses.count).to_not eq 0
end
end
end

View File

@ -1,51 +0,0 @@
require 'rails_helper'
RSpec.describe Api::V1::FollowsController, type: :controller do
render_views
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:follows') }
before do
allow(controller).to receive(:doorkeeper_token) { token }
end
describe 'POST #create' do
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
stub_request(:head, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(:status => 405, :body => "", :headers => {})
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
stub_request(:post, "https://quitter.no/main/salmon/user/7477").to_return(:status => 200, :body => "", :headers => {})
post :create, params: { uri: 'gargron@quitter.no' }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'creates account for remote user' do
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
end
it 'creates a follow relation between user and remote user' do
expect(user.account.following?(Account.find_by(username: 'gargron', domain: 'quitter.no'))).to be true
end
it 'sends a salmon slap to the remote user' do
expect(a_request(:post, "https://quitter.no/main/salmon/user/7477")).to have_been_made
end
it 'subscribes to remote hub' do
expect(a_request(:post, "https://quitter.no/main/push/hub")).to have_been_made
end
it 'returns http success if already following, too' do
post :create, params: { uri: 'gargron@quitter.no' }
expect(response).to have_http_status(200)
end
end
end

View File

@ -364,9 +364,5 @@ describe ApplicationController, type: :controller do
context 'Status' do
include_examples 'cacheable', :status, Status
end
context 'StreamEntry' do
include_examples 'receives :with_includes', :stream_entry, StreamEntry
end
end
end

View File

@ -41,7 +41,7 @@ describe ApplicationController, type: :controller do
it 'sets link headers' do
account = Fabricate(:account, username: 'username', user: Fabricate(:user))
get 'success', params: { account_username: 'username' }
expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/xrd+xml", <http://test.host/users/username.atom>; rel="alternate"; type="application/atom+xml", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
expect(response.headers['Link'].to_s).to eq '<http://test.host/.well-known/webfinger?resource=acct%3Ausername%40cb6e6126.ngrok.io>; rel="lrdd"; type="application/jrd+json", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
end
it 'returns http success' do

View File

@ -38,7 +38,7 @@ describe ApplicationController, type: :controller do
end
context 'with signature header' do
let!(:author) { Fabricate(:account) }
let!(:author) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
context 'without body' do
before do

View File

@ -1,38 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe RemoteUnfollowsController do
render_views
describe '#create' do
subject { post :create, params: { acct: acct } }
let(:current_user) { Fabricate(:user, account: current_account) }
let(:current_account) { Fabricate(:account) }
let(:remote_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }
before do
sign_in current_user
current_account.follow!(remote_account)
stub_request(:post, 'http://example.com/inbox') { { status: 200 } }
end
context 'when successfully unfollow remote account' do
let(:acct) { "acct:#{remote_account.username}@#{remote_account.domain}" }
it do
is_expected.to render_template :success
expect(current_account.following?(remote_account)).to be false
end
end
context 'when fails to unfollow remote account' do
let(:acct) { "acct:#{remote_account.username + '_test'}@#{remote_account.domain}" }
it do
is_expected.to render_template :error
expect(current_account.following?(remote_account)).to be true
end
end
end
end

View File

@ -55,18 +55,6 @@ describe StatusesController do
expect(assigns(:status)).to eq status
end
it 'assigns @stream_entry' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.id }
expect(assigns(:stream_entry)).to eq status.stream_entry
end
it 'assigns @type' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.id }
expect(assigns(:type)).to eq 'status'
end
it 'assigns @ancestors for ancestors of the status if it is a reply' do
ancestor = Fabricate(:status)
status = Fabricate(:status, in_reply_to_id: ancestor.id)
@ -104,7 +92,7 @@ describe StatusesController do
end
it 'assigns @max_descendant_thread_id for the last thread if it is hitting the status limit' do
stub_const 'StatusesController::DESCENDANTS_LIMIT', 1
stub_const 'StatusControllerConcern::DESCENDANTS_LIMIT', 1
status = Fabricate(:status)
child = Fabricate(:status, in_reply_to_id: status.id)
@ -115,7 +103,7 @@ describe StatusesController do
end
it 'assigns @descendant_threads for threads with :next_status key if they are hitting the depth limit' do
stub_const 'StatusesController::DESCENDANTS_DEPTH_LIMIT', 2
stub_const 'StatusControllerConcern::DESCENDANTS_DEPTH_LIMIT', 2
status = Fabricate(:status)
child0 = Fabricate(:status, in_reply_to_id: status.id)
child1 = Fabricate(:status, in_reply_to_id: child0.id)
@ -135,10 +123,10 @@ describe StatusesController do
expect(response).to have_http_status(200)
end
it 'renders stream_entries/show' do
it 'renders statuses/show' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.id }
expect(response).to render_template 'stream_entries/show'
expect(response).to render_template 'statuses/show'
end
end
end

View File

@ -1,95 +0,0 @@
require 'rails_helper'
RSpec.describe StreamEntriesController, type: :controller do
render_views
shared_examples 'before_action' do |route|
context 'when account is not suspended and stream_entry is available' do
it 'assigns instance variables' do
status = Fabricate(:status)
get route, params: { account_username: status.account.username, id: status.stream_entry.id }
expect(assigns(:account)).to eq status.account
expect(assigns(:stream_entry)).to eq status.stream_entry
expect(assigns(:type)).to eq 'status'
end
it 'sets Link headers' do
alice = Fabricate(:account, username: 'alice')
status = Fabricate(:status, account: alice)
get route, params: { account_username: alice.username, id: status.stream_entry.id }
expect(response.headers['Link'].to_s).to eq "<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\"alternate\"; type=\"application/activity+json\""
end
end
context 'when account is suspended' do
it 'returns http status 410' do
account = Fabricate(:account, suspended: true)
status = Fabricate(:status, account: account)
get route, params: { account_username: account.username, id: status.stream_entry.id }
expect(response).to have_http_status(410)
end
end
context 'when activity is nil' do
it 'raises ActiveRecord::RecordNotFound' do
account = Fabricate(:account)
stream_entry = Fabricate.build(:stream_entry, account: account, activity: nil, activity_type: 'Status')
stream_entry.save!(validate: false)
get route, params: { account_username: account.username, id: stream_entry.id }
expect(response).to have_http_status(404)
end
end
context 'when it is hidden and it is not permitted' do
it 'raises ActiveRecord::RecordNotFound' do
status = Fabricate(:status)
user = Fabricate(:user)
status.account.block!(user.account)
status.stream_entry.update!(hidden: true)
sign_in(user)
get route, params: { account_username: status.account.username, id: status.stream_entry.id }
expect(response).to have_http_status(404)
end
end
end
describe 'GET #show' do
include_examples 'before_action', :show
it 'redirects to status page' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.stream_entry.id }
expect(response).to redirect_to(short_account_status_url(status.account, status))
end
it 'returns http success with Atom' do
status = Fabricate(:status)
get :show, params: { account_username: status.account.username, id: status.stream_entry.id }, format: 'atom'
expect(response).to have_http_status(200)
end
end
describe 'GET #embed' do
include_examples 'before_action', :embed
it 'redirects to new embed page' do
status = Fabricate(:status)
get :embed, params: { account_username: status.account.username, id: status.stream_entry.id }
expect(response).to redirect_to(embed_short_account_status_url(status.account, status))
end
end
end