about summary refs log tree commit diff
path: root/spec/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'spec/controllers')
-rw-r--r--spec/controllers/accounts_controller_spec.rb3
-rw-r--r--spec/controllers/activitypub/collections_controller_spec.rb23
-rw-r--r--spec/controllers/activitypub/followers_synchronizations_controller_spec.rb4
-rw-r--r--spec/controllers/activitypub/outboxes_controller_spec.rb16
-rw-r--r--spec/controllers/admin/accounts_controller_spec.rb52
-rw-r--r--spec/controllers/admin/change_email_controller_spec.rb12
-rw-r--r--spec/controllers/admin/confirmations_controller_spec.rb10
-rw-r--r--spec/controllers/admin/instances_controller_spec.rb35
-rw-r--r--spec/controllers/admin/report_notes_controller_spec.rb8
-rw-r--r--spec/controllers/admin/reported_statuses_controller_spec.rb59
-rw-r--r--spec/controllers/admin/reports_controller_spec.rb22
-rw-r--r--spec/controllers/admin/resets_controller_spec.rb4
-rw-r--r--spec/controllers/admin/statuses_controller_spec.rb70
-rw-r--r--spec/controllers/admin/tags_controller_spec.rb12
-rw-r--r--spec/controllers/admin/two_factor_authentications_controller_spec.rb8
-rw-r--r--spec/controllers/api/base_controller_spec.rb2
-rw-r--r--spec/controllers/api/proofs_controller_spec.rb93
-rw-r--r--spec/controllers/api/v1/accounts/credentials_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb6
-rw-r--r--spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb6
-rw-r--r--spec/controllers/api/v1/accounts/lists_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/accounts/notes_controller_spec.rb48
-rw-r--r--spec/controllers/api/v1/accounts/pins_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/accounts/relationships_controller_spec.rb6
-rw-r--r--spec/controllers/api/v1/accounts/search_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/accounts/statuses_controller_spec.rb37
-rw-r--r--spec/controllers/api/v1/accounts_controller_spec.rb38
-rw-r--r--spec/controllers/api/v1/admin/account_actions_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/admin/accounts_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/admin/reports_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/blocks_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/conversations_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/domain_blocks_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/follow_requests_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/instances_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/lists/accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/lists_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/markers_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/media_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/mutes_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/notifications_controller_spec.rb6
-rw-r--r--spec/controllers/api/v1/polls/votes_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/polls_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/reports_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/bookmarks_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/favourites_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/histories_controller_spec.rb29
-rw-r--r--spec/controllers/api/v1/statuses/mutes_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/pins_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/reblogs_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/statuses/sources_controller_spec.rb29
-rw-r--r--spec/controllers/api/v1/statuses_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/timelines/home_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/timelines/list_controller_spec.rb4
-rw-r--r--spec/controllers/api/v1/timelines/public_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/timelines/tag_controller_spec.rb2
-rw-r--r--spec/controllers/api/v1/trends/tags_controller_spec.rb22
-rw-r--r--spec/controllers/api/v1/trends_controller_spec.rb18
-rw-r--r--spec/controllers/api/v2/search_controller_spec.rb2
-rw-r--r--spec/controllers/application_controller_spec.rb6
-rw-r--r--spec/controllers/auth/registrations_controller_spec.rb2
-rw-r--r--spec/controllers/auth/sessions_controller_spec.rb149
-rw-r--r--spec/controllers/authorize_interactions_controller_spec.rb3
-rw-r--r--spec/controllers/concerns/account_controller_concern_spec.rb31
-rw-r--r--spec/controllers/concerns/accountable_concern_spec.rb8
-rw-r--r--spec/controllers/follower_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/following_accounts_controller_spec.rb2
-rw-r--r--spec/controllers/home_controller_spec.rb6
-rw-r--r--spec/controllers/media_controller_spec.rb63
-rw-r--r--spec/controllers/settings/deletes_controller_spec.rb8
-rw-r--r--spec/controllers/settings/identity_proofs_controller_spec.rb186
-rw-r--r--spec/controllers/settings/migrations_controller_spec.rb3
-rw-r--r--spec/controllers/settings/profiles_controller_spec.rb14
-rw-r--r--spec/controllers/statuses_cleanup_controller_spec.rb27
-rw-r--r--spec/controllers/well_known/keybase_proof_config_controller_spec.rb15
-rw-r--r--spec/controllers/well_known/webfinger_controller_spec.rb4
78 files changed, 683 insertions, 602 deletions
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index ac426b01e..73d124029 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe AccountsController, type: :controller do
   render_views
 
-  let(:account) { Fabricate(:user).account }
+  let(:account) { Fabricate(:account) }
 
   shared_examples 'cachable response' do
     it 'does not set cookies' do
@@ -35,6 +35,7 @@ RSpec.describe AccountsController, type: :controller do
     before do
       status_media.media_attachments << Fabricate(:media_attachment, account: account, type: :image)
       account.pinned_statuses << status_pinned
+      account.pinned_statuses << status_private
     end
 
     shared_examples 'preliminary checks' do
diff --git a/spec/controllers/activitypub/collections_controller_spec.rb b/spec/controllers/activitypub/collections_controller_spec.rb
index d584136ff..21a033945 100644
--- a/spec/controllers/activitypub/collections_controller_spec.rb
+++ b/spec/controllers/activitypub/collections_controller_spec.rb
@@ -4,6 +4,7 @@ require 'rails_helper'
 
 RSpec.describe ActivityPub::CollectionsController, type: :controller do
   let!(:account) { Fabricate(:account) }
+  let!(:private_pinned) { Fabricate(:status, account: account, text: 'secret private stuff', visibility: :private) }
   let(:remote_account) { nil }
 
   shared_examples 'cachable response' do
@@ -27,6 +28,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
 
     Fabricate(:status_pin, account: account)
     Fabricate(:status_pin, account: account)
+    Fabricate(:status_pin, account: account, status: private_pinned)
     Fabricate(:status, account: account, visibility: :private)
   end
 
@@ -50,7 +52,15 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
 
         it 'returns orderedItems with pinned statuses' do
           expect(body[:orderedItems]).to be_an Array
-          expect(body[:orderedItems].size).to eq 2
+          expect(body[:orderedItems].size).to eq 3
+        end
+
+        it 'includes URI of private pinned status' do
+          expect(body[:orderedItems]).to include(ActivityPub::TagManager.instance.uri_for(private_pinned))
+        end
+
+        it 'does not include contents of private pinned status' do
+          expect(response.body).not_to include(private_pinned.text)
         end
 
         context 'when account is permanently suspended' do
@@ -96,7 +106,16 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
           it 'returns orderedItems with pinned statuses' do
             json = body_as_json
             expect(json[:orderedItems]).to be_an Array
-            expect(json[:orderedItems].size).to eq 2
+            expect(json[:orderedItems].size).to eq 3
+          end
+
+          it 'includes URI of private pinned status' do
+            json = body_as_json
+            expect(json[:orderedItems]).to include(ActivityPub::TagManager.instance.uri_for(private_pinned))
+          end
+
+          it 'does not include contents of private pinned status' do
+            expect(response.body).not_to include(private_pinned.text)
           end
         end
 
diff --git a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
index d373f56bd..3a382ff27 100644
--- a/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
+++ b/spec/controllers/activitypub/followers_synchronizations_controller_spec.rb
@@ -5,11 +5,13 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controll
   let!(:follower_1) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
   let!(:follower_2) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
   let!(:follower_3) { Fabricate(:account, domain: 'foo.com', uri: 'https://foo.com/users/a') }
+  let!(:follower_4) { Fabricate(:account, username: 'instance-actor', domain: 'example.com', uri: 'https://example.com') }
 
   before do
     follower_1.follow!(account)
     follower_2.follow!(account)
     follower_3.follow!(account)
+    follower_4.follow!(account)
   end
 
   before do
@@ -45,7 +47,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controll
 
       it 'returns orderedItems with followers from example.com' do
         expect(body[:orderedItems]).to be_an Array
-        expect(body[:orderedItems].sort).to eq [follower_1.uri, follower_2.uri]
+        expect(body[:orderedItems].sort).to eq [follower_4.uri, follower_1.uri, follower_2.uri]
       end
 
       it 'returns private Cache-Control header' do
diff --git a/spec/controllers/activitypub/outboxes_controller_spec.rb b/spec/controllers/activitypub/outboxes_controller_spec.rb
index d23f2c17c..1722690db 100644
--- a/spec/controllers/activitypub/outboxes_controller_spec.rb
+++ b/spec/controllers/activitypub/outboxes_controller_spec.rb
@@ -55,6 +55,10 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
 
         it_behaves_like 'cachable response'
 
+        it 'does not have a Vary header' do
+          expect(response.headers['Vary']).to be_nil
+        end
+
         context 'when account is permanently suspended' do
           before do
             account.suspend!
@@ -96,6 +100,10 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
 
         it_behaves_like 'cachable response'
 
+        it 'returns Vary header with Signature' do
+          expect(response.headers['Vary']).to include 'Signature'
+        end
+
         context 'when account is permanently suspended' do
           before do
             account.suspend!
@@ -144,7 +152,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns private Cache-Control header' do
-          expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
+          expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
         end
       end
 
@@ -170,7 +178,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns private Cache-Control header' do
-          expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
+          expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
         end
       end
 
@@ -195,7 +203,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns private Cache-Control header' do
-          expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
+          expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
         end
       end
 
@@ -220,7 +228,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
         end
 
         it 'returns private Cache-Control header' do
-          expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
+          expect(response.headers['Cache-Control']).to eq 'max-age=60, private'
         end
       end
     end
diff --git a/spec/controllers/admin/accounts_controller_spec.rb b/spec/controllers/admin/accounts_controller_spec.rb
index 608606ff9..0f71d697c 100644
--- a/spec/controllers/admin/accounts_controller_spec.rb
+++ b/spec/controllers/admin/accounts_controller_spec.rb
@@ -21,12 +21,9 @@ RSpec.describe Admin::AccountsController, type: :controller do
       expect(AccountFilter).to receive(:new) do |params|
         h = params.to_h
 
-        expect(h[:local]).to eq '1'
-        expect(h[:remote]).to eq '1'
+        expect(h[:origin]).to eq 'local'
         expect(h[:by_domain]).to eq 'domain'
-        expect(h[:active]).to eq '1'
-        expect(h[:silenced]).to eq '1'
-        expect(h[:suspended]).to eq '1'
+        expect(h[:status]).to eq 'active'
         expect(h[:username]).to eq 'username'
         expect(h[:display_name]).to eq 'display name'
         expect(h[:email]).to eq 'local-part@domain'
@@ -36,12 +33,9 @@ RSpec.describe Admin::AccountsController, type: :controller do
       end
 
       get :index, params: {
-        local: '1',
-        remote: '1',
+        origin: 'local',
         by_domain: 'domain',
-        active: '1',
-        silenced: '1',
-        suspended: '1',
+        status: 'active',
         username: 'username',
         display_name: 'display name',
         email: 'local-part@domain',
@@ -67,7 +61,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
 
   describe 'GET #show' do
     let(:current_user) { Fabricate(:user, admin: true) }
-    let(:account) { Fabricate(:account, username: 'bob') }
+    let(:account) { Fabricate(:account) }
 
     it 'returns http success' do
       get :show, params: { id: account.id }
@@ -79,7 +73,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
     subject { post :memorialize, params: { id: account.id } }
 
     let(:current_user) { Fabricate(:user, admin: current_user_admin) }
-    let(:account) { Fabricate(:account, user: user) }
+    let(:account) { user.account }
     let(:user) { Fabricate(:user, admin: target_user_admin) }
 
     context 'when user is admin' do
@@ -131,7 +125,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
     subject { post :enable, params: { id: account.id } }
 
     let(:current_user) { Fabricate(:user, admin: admin) }
-    let(:account) { Fabricate(:account, user: user) }
+    let(:account) { user.account }
     let(:user) { Fabricate(:user, disabled: true) }
 
     context 'when user is admin' do
@@ -198,4 +192,36 @@ RSpec.describe Admin::AccountsController, type: :controller do
       end
     end
   end
+
+  describe 'POST #unblock_email' do
+    subject do
+      -> { post :unblock_email, params: { id: account.id } }
+    end
+
+    let(:current_user) { Fabricate(:user, admin: admin) }
+    let(:account) { Fabricate(:account, suspended: true) }
+    let!(:email_block) { Fabricate(:canonical_email_block, reference_account: account) }
+
+    context 'when user is admin' do
+      let(:admin) { true }
+
+      it 'succeeds in removing email blocks' do
+        is_expected.to change { CanonicalEmailBlock.where(reference_account: account).count }.from(1).to(0)
+      end
+
+      it 'redirects to admin account path' do
+        subject.call
+        expect(response).to redirect_to admin_account_path(account.id)
+      end
+    end
+
+    context 'when user is not admin' do
+      let(:admin) { false }
+
+      it 'fails to remove avatar' do
+        subject.call
+        expect(response).to have_http_status :forbidden
+      end
+    end
+  end
 end
diff --git a/spec/controllers/admin/change_email_controller_spec.rb b/spec/controllers/admin/change_email_controller_spec.rb
index 31df0f0fc..e7f3f7c97 100644
--- a/spec/controllers/admin/change_email_controller_spec.rb
+++ b/spec/controllers/admin/change_email_controller_spec.rb
@@ -11,10 +11,9 @@ RSpec.describe Admin::ChangeEmailsController, type: :controller do
 
   describe "GET #show" do
     it "returns http success" do
-      account = Fabricate(:account)
-      user = Fabricate(:user, account: account)
+      user = Fabricate(:user)
 
-      get :show, params: { account_id: account.id }
+      get :show, params: { account_id: user.account.id }
 
       expect(response).to have_http_status(200)
     end
@@ -26,12 +25,11 @@ RSpec.describe Admin::ChangeEmailsController, type: :controller do
     end
 
     it "returns http success" do
-      account = Fabricate(:account)
-      user = Fabricate(:user, account: account)
+      user = Fabricate(:user)
 
       previous_email = user.email
 
-      post :update, params: { account_id: account.id, user: { unconfirmed_email: 'test@example.com' } }
+      post :update, params: { account_id: user.account.id, user: { unconfirmed_email: 'test@example.com' } }
 
       user.reload
 
@@ -41,7 +39,7 @@ RSpec.describe Admin::ChangeEmailsController, type: :controller do
 
       expect(UserMailer).to have_received(:confirmation_instructions).with(user, user.confirmation_token, { to: 'test@example.com' })
 
-      expect(response).to redirect_to(admin_account_path(account.id))
+      expect(response).to redirect_to(admin_account_path(user.account.id))
     end
   end
 end
diff --git a/spec/controllers/admin/confirmations_controller_spec.rb b/spec/controllers/admin/confirmations_controller_spec.rb
index eec2b2f5c..5b4f7e925 100644
--- a/spec/controllers/admin/confirmations_controller_spec.rb
+++ b/spec/controllers/admin/confirmations_controller_spec.rb
@@ -9,9 +9,8 @@ RSpec.describe Admin::ConfirmationsController, type: :controller do
 
   describe 'POST #create' do
     it 'confirms the user' do
-      account = Fabricate(:account)
-      user = Fabricate(:user, confirmed_at: false, account: account)
-      post :create, params: { account_id: account.id }
+      user = Fabricate(:user, confirmed_at: false)
+      post :create, params: { account_id: user.account.id }
 
       expect(response).to redirect_to(admin_accounts_path)
       expect(user.reload).to be_confirmed
@@ -32,10 +31,9 @@ RSpec.describe Admin::ConfirmationsController, type: :controller do
   end
 
   describe 'POST #resernd' do
-    subject { post :resend, params: { account_id: account.id } }
+    subject { post :resend, params: { account_id: user.account.id } }
 
-    let(:account) { Fabricate(:account) }
-    let!(:user) { Fabricate(:user, confirmed_at: confirmed_at, account: account) }
+    let!(:user) { Fabricate(:user, confirmed_at: confirmed_at) }
 
     before do
       allow(UserMailer).to receive(:confirmation_instructions) { double(:email, deliver_later: nil) }
diff --git a/spec/controllers/admin/instances_controller_spec.rb b/spec/controllers/admin/instances_controller_spec.rb
index 8c0b309f2..53427b874 100644
--- a/spec/controllers/admin/instances_controller_spec.rb
+++ b/spec/controllers/admin/instances_controller_spec.rb
@@ -3,8 +3,14 @@ require 'rails_helper'
 RSpec.describe Admin::InstancesController, type: :controller do
   render_views
 
+  let(:current_user) { Fabricate(:user, admin: true) }
+
+  let!(:account)     { Fabricate(:account, domain: 'popular') }
+  let!(:account2)    { Fabricate(:account, domain: 'popular') }
+  let!(:account3)    { Fabricate(:account, domain: 'less.popular') }
+
   before do
-    sign_in Fabricate(:user, admin: true), scope: :user
+    sign_in current_user, scope: :user
   end
 
   describe 'GET #index' do
@@ -16,10 +22,6 @@ RSpec.describe Admin::InstancesController, type: :controller do
     end
 
     it 'renders instances' do
-      Fabricate(:account, domain: 'popular')
-      Fabricate(:account, domain: 'popular')
-      Fabricate(:account, domain: 'less.popular')
-
       get :index, params: { page: 2 }
 
       instances = assigns(:instances).to_a
@@ -29,4 +31,27 @@ RSpec.describe Admin::InstancesController, type: :controller do
       expect(response).to have_http_status(200)
     end
   end
+
+  describe 'DELETE #destroy' do
+    subject { delete :destroy, params: { id: Instance.first.id } }
+
+    let(:current_user) { Fabricate(:user, admin: admin) }
+    let(:account) { Fabricate(:account) }
+
+    context 'when user is admin' do
+      let(:admin) { true }
+
+      it 'succeeds in purging instance' do
+        is_expected.to redirect_to admin_instances_path
+      end
+    end
+
+    context 'when user is not admin' do
+      let(:admin) { false }
+
+      it 'fails to purge instance' do
+        is_expected.to have_http_status :forbidden
+      end
+    end
+  end
 end
diff --git a/spec/controllers/admin/report_notes_controller_spec.rb b/spec/controllers/admin/report_notes_controller_spec.rb
index ec5872c7d..c0013f41a 100644
--- a/spec/controllers/admin/report_notes_controller_spec.rb
+++ b/spec/controllers/admin/report_notes_controller_spec.rb
@@ -12,11 +12,11 @@ describe Admin::ReportNotesController do
   describe 'POST #create' do
     subject { post :create, params: params }
 
-    let(:report) { Fabricate(:report, action_taken: action_taken, action_taken_by_account_id: account_id) }
+    let(:report) { Fabricate(:report, action_taken_at: action_taken, action_taken_by_account_id: account_id) }
 
     context 'when parameter is valid' do
       context 'when report is unsolved' do
-        let(:action_taken) { false }
+        let(:action_taken) { nil }
         let(:account_id) { nil }
 
         context 'when create_and_resolve flag is on' do
@@ -41,7 +41,7 @@ describe Admin::ReportNotesController do
       end
 
       context 'when report is resolved' do
-        let(:action_taken) { true }
+        let(:action_taken) { Time.now.utc }
         let(:account_id) { user.account.id }
 
         context 'when create_and_unresolve flag is on' do
@@ -68,7 +68,7 @@ describe Admin::ReportNotesController do
 
     context 'when parameter is invalid' do
       let(:params) { { report_note: { content: '', report_id: report.id } } }
-      let(:action_taken) { false }
+      let(:action_taken) { nil }
       let(:account_id) { nil }
 
       it 'renders admin/reports/show' do
diff --git a/spec/controllers/admin/reported_statuses_controller_spec.rb b/spec/controllers/admin/reported_statuses_controller_spec.rb
deleted file mode 100644
index 2a1598123..000000000
--- a/spec/controllers/admin/reported_statuses_controller_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'rails_helper'
-
-describe Admin::ReportedStatusesController do
-  render_views
-
-  let(:user) { Fabricate(:user, admin: true) }
-  let(:report) { Fabricate(:report, status_ids: [status.id]) }
-  let(:status) { Fabricate(:status) }
-
-  before do
-    sign_in user, scope: :user
-  end
-
-  describe 'POST #create' do
-    subject do
-      -> { post :create, params: { :report_id => report, action => '', :form_status_batch => { status_ids: status_ids } } }
-    end
-
-    let(:action) { 'nsfw_on' }
-    let(:status_ids) { [status.id] }
-    let(:status) { Fabricate(:status, sensitive: !sensitive) }
-    let(:sensitive) { true }
-    let!(:media_attachment) { Fabricate(:media_attachment, status: status) }
-
-    context 'when action is nsfw_on' do
-      it 'updates sensitive column' do
-        is_expected.to change {
-          status.reload.sensitive
-        }.from(false).to(true)
-      end
-    end
-
-    context 'when action is nsfw_off' do
-      let(:action) { 'nsfw_off' }
-      let(:sensitive) { false }
-
-      it 'updates sensitive column' do
-        is_expected.to change {
-          status.reload.sensitive
-        }.from(true).to(false)
-      end
-    end
-
-    context 'when action is delete' do
-      let(:action) { 'delete' }
-
-      it 'removes a status' do
-        allow(RemovalWorker).to receive(:perform_async)
-        subject.call
-        expect(RemovalWorker).to have_received(:perform_async).with(status_ids.first, immediate: true)
-      end
-    end
-
-    it 'redirects to report page' do
-      subject.call
-      expect(response).to redirect_to(admin_report_path(report))
-    end
-  end
-end
diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb
index 49d3e9707..d421f0739 100644
--- a/spec/controllers/admin/reports_controller_spec.rb
+++ b/spec/controllers/admin/reports_controller_spec.rb
@@ -10,8 +10,8 @@ describe Admin::ReportsController do
 
   describe 'GET #index' do
     it 'returns http success with no filters' do
-      specified = Fabricate(:report, action_taken: false)
-      Fabricate(:report, action_taken: true)
+      specified = Fabricate(:report, action_taken_at: nil)
+      Fabricate(:report, action_taken_at: Time.now.utc)
 
       get :index
 
@@ -22,10 +22,10 @@ describe Admin::ReportsController do
     end
 
     it 'returns http success with resolved filter' do
-      specified = Fabricate(:report, action_taken: true)
-      Fabricate(:report, action_taken: false)
+      specified = Fabricate(:report, action_taken_at: Time.now.utc)
+      Fabricate(:report, action_taken_at: nil)
 
-      get :index, params: { resolved: 1 }
+      get :index, params: { resolved: '1' }
 
       reports = assigns(:reports).to_a
       expect(reports.size).to eq 1
@@ -54,15 +54,7 @@ describe Admin::ReportsController do
       expect(response).to redirect_to(admin_reports_path)
       report.reload
       expect(report.action_taken_by_account).to eq user.account
-      expect(report.action_taken).to eq true
-    end
-
-    it 'sets trust level when the report is an antispam one' do
-      report = Fabricate(:report, account: Account.representative)
-
-      put :resolve, params: { id: report }
-      report.reload
-      expect(report.target_account.trust_level).to eq Account::TRUST_LEVELS[:trusted]
+      expect(report.action_taken?).to eq true
     end
   end
 
@@ -74,7 +66,7 @@ describe Admin::ReportsController do
       expect(response).to redirect_to(admin_report_path(report))
       report.reload
       expect(report.action_taken_by_account).to eq nil
-      expect(report.action_taken).to eq false
+      expect(report.action_taken?).to eq false
     end
   end
 
diff --git a/spec/controllers/admin/resets_controller_spec.rb b/spec/controllers/admin/resets_controller_spec.rb
index a20a460bd..28510b5af 100644
--- a/spec/controllers/admin/resets_controller_spec.rb
+++ b/spec/controllers/admin/resets_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Admin::ResetsController do
   render_views
 
-  let(:account) { Fabricate(:account, user: Fabricate(:user)) }
+  let(:account) { Fabricate(:account) }
   before do
     sign_in Fabricate(:user, admin: true), scope: :user
   end
@@ -16,7 +16,7 @@ describe Admin::ResetsController do
 
       post :create, params: { account_id: account.id }
 
-      expect(response).to redirect_to(admin_accounts_path)
+      expect(response).to redirect_to(admin_account_path(account.id))
     end
   end
 end
diff --git a/spec/controllers/admin/statuses_controller_spec.rb b/spec/controllers/admin/statuses_controller_spec.rb
index d9690d83f..de32fd18e 100644
--- a/spec/controllers/admin/statuses_controller_spec.rb
+++ b/spec/controllers/admin/statuses_controller_spec.rb
@@ -8,6 +8,9 @@ describe Admin::StatusesController do
   let!(:status) { Fabricate(:status, account: account) }
   let(:media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
   let!(:media_attachment) { Fabricate(:media_attachment, account: account, status: media_attached_status) }
+  let(:last_media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
+  let!(:last_media_attachment) { Fabricate(:media_attachment, account: account, status: last_media_attached_status) }
+  let!(:last_status) { Fabricate(:status, account: account) }
   let(:sensitive) { true }
 
   before do
@@ -15,63 +18,46 @@ describe Admin::StatusesController do
   end
 
   describe 'GET #index' do
-    it 'returns http success with no media' do
-      get :index, params: { account_id: account.id }
+    context do
+      before do
+        get :index, params: { account_id: account.id }
+      end
 
-      statuses = assigns(:statuses).to_a
-      expect(statuses.size).to eq 2
-      expect(response).to have_http_status(200)
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
     end
 
-    it 'returns http success with media' do
-      get :index, params: { account_id: account.id, media: true }
+    context 'filtering by media' do
+      before do
+        get :index, params: { account_id: account.id, media: '1' }
+      end
 
-      statuses = assigns(:statuses).to_a
-      expect(statuses.size).to eq 1
-      expect(response).to have_http_status(200)
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
     end
   end
 
-  describe 'POST #create' do
-    subject do
-      -> { post :create, params: { :account_id => account.id, action => '', :form_status_batch => { status_ids: status_ids } } }
+  describe 'POST #batch' do
+    before do
+      post :batch, params: { :account_id => account.id, action => '', :admin_status_batch_action => { status_ids: status_ids } }
     end
 
-    let(:action) { 'nsfw_on' }
     let(:status_ids) { [media_attached_status.id] }
 
-    context 'when action is nsfw_on' do
-      it 'updates sensitive column' do
-        is_expected.to change {
-          media_attached_status.reload.sensitive
-        }.from(false).to(true)
-      end
-    end
+    context 'when action is report' do
+      let(:action) { 'report' }
 
-    context 'when action is nsfw_off' do
-      let(:action) { 'nsfw_off' }
-      let(:sensitive) { false }
-
-      it 'updates sensitive column' do
-        is_expected.to change {
-          media_attached_status.reload.sensitive
-        }.from(true).to(false)
+      it 'creates a report' do
+        report = Report.last
+        expect(report.target_account_id).to eq account.id
+        expect(report.status_ids).to eq status_ids
       end
-    end
-
-    context 'when action is delete' do
-      let(:action) { 'delete' }
 
-      it 'removes a status' do
-        allow(RemovalWorker).to receive(:perform_async)
-        subject.call
-        expect(RemovalWorker).to have_received(:perform_async).with(status_ids.first, immediate: true)
+      it 'redirects to report page' do
+        expect(response).to redirect_to(admin_report_path(Report.last.id))
       end
     end
-
-    it 'redirects to account statuses page' do
-      subject.call
-      expect(response).to redirect_to(admin_account_statuses_path(account.id))
-    end
   end
 end
diff --git a/spec/controllers/admin/tags_controller_spec.rb b/spec/controllers/admin/tags_controller_spec.rb
index 9145d887d..85c801a9c 100644
--- a/spec/controllers/admin/tags_controller_spec.rb
+++ b/spec/controllers/admin/tags_controller_spec.rb
@@ -9,18 +9,6 @@ RSpec.describe Admin::TagsController, type: :controller do
     sign_in Fabricate(:user, admin: true)
   end
 
-  describe 'GET #index' do
-    let!(:tag) { Fabricate(:tag) }
-
-    before do
-      get :index
-    end
-
-    it 'returns status 200' do
-      expect(response).to have_http_status(200)
-    end
-  end
-
   describe 'GET #show' do
     let!(:tag) { Fabricate(:tag) }
 
diff --git a/spec/controllers/admin/two_factor_authentications_controller_spec.rb b/spec/controllers/admin/two_factor_authentications_controller_spec.rb
index b0e82d3d6..c65095729 100644
--- a/spec/controllers/admin/two_factor_authentications_controller_spec.rb
+++ b/spec/controllers/admin/two_factor_authentications_controller_spec.rb
@@ -15,12 +15,12 @@ describe Admin::TwoFactorAuthenticationsController do
         user.update(otp_required_for_login: true)
       end
 
-      it 'redirects to admin accounts page' do
+      it 'redirects to admin account page' do
         delete :destroy, params: { user_id: user.id }
 
         user.reload
         expect(user.otp_enabled?).to eq false
-        expect(response).to redirect_to(admin_accounts_path)
+        expect(response).to redirect_to(admin_account_path(user.account_id))
       end
     end
 
@@ -38,13 +38,13 @@ describe Admin::TwoFactorAuthenticationsController do
                   nickname: 'Security Key')
       end
 
-      it 'redirects to admin accounts page' do
+      it 'redirects to admin account page' do
         delete :destroy, params: { user_id: user.id }
 
         user.reload
         expect(user.otp_enabled?).to eq false
         expect(user.webauthn_enabled?).to eq false
-        expect(response).to redirect_to(admin_accounts_path)
+        expect(response).to redirect_to(admin_account_path(user.account_id))
       end
     end
   end
diff --git a/spec/controllers/api/base_controller_spec.rb b/spec/controllers/api/base_controller_spec.rb
index 05a42d1c1..c286b8cbf 100644
--- a/spec/controllers/api/base_controller_spec.rb
+++ b/spec/controllers/api/base_controller_spec.rb
@@ -28,7 +28,7 @@ describe Api::BaseController do
   end
 
   describe 'non-functional accounts handling' do
-    let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+    let(:user)  { Fabricate(:user) }
     let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
 
     controller do
diff --git a/spec/controllers/api/proofs_controller_spec.rb b/spec/controllers/api/proofs_controller_spec.rb
deleted file mode 100644
index 2fe615005..000000000
--- a/spec/controllers/api/proofs_controller_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-require 'rails_helper'
-
-describe Api::ProofsController do
-  let(:alice) { Fabricate(:account, username: 'alice') }
-
-  before do
-    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":false}')
-    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=crypto_alice&sig_hash=111111111111111111111111111111111111111111111111111111111111111111&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
-    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_valid.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
-    stub_request(:get, 'https://keybase.io/_/api/1.0/sig/proof_live.json?domain=cb6e6126.ngrok.io&kb_username=hidden_alice&sig_hash=222222222222222222222222222222222222222222222222222222222222222222&username=alice').to_return(status: 200, body: '{"proof_valid":true,"proof_live":true}')
-  end
-
-  describe 'GET #index' do
-    describe 'with a non-existent username' do
-      it '404s' do
-        get :index, params: { username: 'nonexistent', provider: 'keybase' }
-
-        expect(response).to have_http_status(:not_found)
-      end
-    end
-
-    describe 'with a user that has no proofs' do
-      it 'is an empty list of signatures' do
-        get :index, params: { username: alice.username, provider: 'keybase' }
-
-        expect(body_as_json[:signatures]).to eq []
-      end
-    end
-
-    describe 'with a user that has a live, valid proof' do
-      let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
-      let(:kb_name1) { 'crypto_alice' }
-
-      before do
-        Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
-      end
-
-      it 'is a list with that proof in it' do
-        get :index, params: { username: alice.username, provider: 'keybase' }
-
-        expect(body_as_json[:signatures]).to eq [
-          { kb_username: kb_name1, sig_hash: token1 },
-        ]
-      end
-
-      describe 'add one that is neither live nor valid' do
-        let(:token2) { '222222222222222222222222222222222222222222222222222222222222222222' }
-        let(:kb_name2) { 'hidden_alice' }
-
-        before do
-          Fabricate(:account_identity_proof, account: alice, verified: false, live: false, token: token2, provider_username: kb_name2)
-        end
-
-        it 'is a list with both proofs' do
-          get :index, params: { username: alice.username, provider: 'keybase' }
-
-          expect(body_as_json[:signatures]).to eq [
-            { kb_username: kb_name1, sig_hash: token1 },
-            { kb_username: kb_name2, sig_hash: token2 },
-          ]
-        end
-      end
-    end
-
-    describe 'a user that has an avatar' do
-      let(:alice) { Fabricate(:account, username: 'alice', avatar: attachment_fixture('avatar.gif')) }
-
-      context 'and a proof' do
-        let(:token1) { '111111111111111111111111111111111111111111111111111111111111111111' }
-        let(:kb_name1) { 'crypto_alice' }
-
-        before do
-          Fabricate(:account_identity_proof, account: alice, verified: true, live: true, token: token1, provider_username: kb_name1)
-          get :index, params: { username: alice.username, provider: 'keybase' }
-        end
-
-        it 'has two keys: signatures and avatar' do
-          expect(body_as_json.keys).to match_array [:signatures, :avatar]
-        end
-
-        it 'has the correct signatures' do
-          expect(body_as_json[:signatures]).to eq [
-            { kb_username: kb_name1, sig_hash: token1 },
-          ]
-        end
-
-        it 'has the correct avatar url' do
-          expect(body_as_json[:avatar]).to match "https://cb6e6126.ngrok.io#{alice.avatar.url}"
-        end
-      end
-    end
-  end
-end
diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
index 1b29772c3..aae35ce38 100644
--- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::CredentialsController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
   context 'with an oauth token' do
diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
index 482a19ef2..1e6e1d8e0 100644
--- a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::FollowerAccountsController do
   render_views
 
-  let(:user)    { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)    { Fabricate(:user) }
   let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
   let(:account) { Fabricate(:account) }
   let(:alice)   { Fabricate(:account) }
@@ -49,10 +49,10 @@ describe Api::V1::Accounts::FollowerAccountsController do
     end
 
     context 'when requesting user is the account owner' do
-      let(:user) { Fabricate(:user, account: account) }
+      let(:user) { account.user }
 
       it 'returns all accounts, including muted accounts' do
-        user.account.mute!(bob)
+        account.mute!(bob)
         get :index, params: { account_id: account.id, limit: 2 }
 
         expect(body_as_json.size).to eq 2
diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
index e35b625fe..cc962c6ee 100644
--- a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::FollowingAccountsController do
   render_views
 
-  let(:user)    { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)    { Fabricate(:user) }
   let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
   let(:account) { Fabricate(:account) }
   let(:alice)   { Fabricate(:account) }
@@ -49,10 +49,10 @@ describe Api::V1::Accounts::FollowingAccountsController do
     end
 
     context 'when requesting user is the account owner' do
-      let(:user) { Fabricate(:user, account: account) }
+      let(:user) { account.user }
 
       it 'returns all accounts, including muted accounts' do
-        user.account.mute!(bob)
+        account.mute!(bob)
         get :index, params: { account_id: account.id, limit: 2 }
 
         expect(body_as_json.size).to eq 2
diff --git a/spec/controllers/api/v1/accounts/lists_controller_spec.rb b/spec/controllers/api/v1/accounts/lists_controller_spec.rb
index baafea8e6..d71485633 100644
--- a/spec/controllers/api/v1/accounts/lists_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/lists_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::ListsController do
   render_views
 
-  let(:user)    { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)    { Fabricate(:user) }
   let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') }
   let(:account) { Fabricate(:account) }
   let(:list)    { Fabricate(:list, account: user.account) }
diff --git a/spec/controllers/api/v1/accounts/notes_controller_spec.rb b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
new file mode 100644
index 000000000..47d595c70
--- /dev/null
+++ b/spec/controllers/api/v1/accounts/notes_controller_spec.rb
@@ -0,0 +1,48 @@
+require 'rails_helper'
+
+describe Api::V1::Accounts::NotesController do
+  render_views
+
+  let(:user)    { Fabricate(:user) }
+  let(:token)   { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts') }
+  let(:account) { Fabricate(:account) }
+  let(:comment) { 'foo' }
+
+  before do
+    allow(controller).to receive(:doorkeeper_token) { token }
+  end
+
+  describe 'POST #create' do
+    subject do
+      post :create, params: { account_id: account.id, comment: comment }
+    end
+
+    context 'when account note has reasonable length' do
+      let(:comment) { 'foo' }
+
+      it 'returns http success' do
+        subject
+        expect(response).to have_http_status(200)
+      end
+
+      it 'updates account note' do
+        subject
+        expect(AccountNote.find_by(account_id: user.account.id, target_account_id: account.id).comment).to eq comment
+      end
+    end
+
+    context 'when account note exceends allowed length' do
+      let(:comment) { 'a' * 2_001 }
+
+      it 'returns 422' do
+        subject
+        expect(response).to have_http_status(422)
+      end
+
+      it 'does not create account note' do
+        subject
+        expect(AccountNote.where(account_id: user.account.id, target_account_id: account.id).exists?).to be_falsey
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/accounts/pins_controller_spec.rb b/spec/controllers/api/v1/accounts/pins_controller_spec.rb
index c71935df2..19bba093e 100644
--- a/spec/controllers/api/v1/accounts/pins_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/pins_controller_spec.rb
@@ -3,8 +3,8 @@
 require 'rails_helper'
 
 RSpec.describe Api::V1::Accounts::PinsController, type: :controller do
-  let(:john)  { Fabricate(:user, account: Fabricate(:account, username: 'john')) }
-  let(:kevin) { Fabricate(:user, account: Fabricate(:account, username: 'kevin')) }
+  let(:john)  { Fabricate(:user) }
+  let(:kevin) { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: john.id, scopes: 'write:accounts') }
 
   before do
diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
index fe715ff62..69ad0d061 100644
--- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::RelationshipsController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:follows') }
 
   before do
@@ -11,8 +11,8 @@ describe Api::V1::Accounts::RelationshipsController do
   end
 
   describe 'GET #index' do
-    let(:simon) { Fabricate(:user, email: 'simon@example.com', account: Fabricate(:account, username: 'simon')).account }
-    let(:lewis) { Fabricate(:user, email: 'lewis@example.com', account: Fabricate(:account, username: 'lewis')).account }
+    let(:simon) { Fabricate(:account) }
+    let(:lewis) { Fabricate(:account) }
 
     before do
       user.account.follow!(simon)
diff --git a/spec/controllers/api/v1/accounts/search_controller_spec.rb b/spec/controllers/api/v1/accounts/search_controller_spec.rb
index 8ff2b17de..5b23bff68 100644
--- a/spec/controllers/api/v1/accounts/search_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/search_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::Accounts::SearchController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') }
 
   before do
diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
index 693cd1ac6..348de08c2 100644
--- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Accounts::StatusesController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
 
   before do
@@ -39,7 +39,7 @@ describe Api::V1::Accounts::StatusesController do
       end
     end
 
-    context 'with only pinned' do
+    context 'with only own pinned' do
       before do
         Fabricate(:status_pin, account: user.account, status: Fabricate(:status, account: user.account))
       end
@@ -50,5 +50,38 @@ describe Api::V1::Accounts::StatusesController do
         expect(response).to have_http_status(200)
       end
     end
+
+    context "with someone else's pinned statuses" do
+      let(:account)        { Fabricate(:account, username: 'bob', domain: 'example.com') }
+      let(:status)         { Fabricate(:status, account: account) }
+      let(:private_status) { Fabricate(:status, account: account, visibility: :private) }
+      let!(:pin)           { Fabricate(:status_pin, account: account, status: status) }
+      let!(:private_pin)   { Fabricate(:status_pin, account: account, status: private_status) }
+
+      it 'returns http success' do
+        get :index, params: { account_id: account.id, pinned: true }
+        expect(response).to have_http_status(200)
+      end
+
+      context 'when user does not follow account' do
+        it 'lists the public status only' do
+          get :index, params: { account_id: account.id, pinned: true }
+          json = body_as_json
+          expect(json.map { |item| item[:id].to_i }).to eq [status.id]
+        end
+      end
+
+      context 'when user follows account' do
+        before do
+          user.account.follow!(account)
+        end
+
+        it 'lists both the public and the private statuses' do
+          get :index, params: { account_id: account.id, pinned: true }
+          json = body_as_json
+          expect(json.map { |item| item[:id].to_i }.sort).to eq [status.id, private_status.id].sort
+        end
+      end
+    end
   end
 end
diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb
index d9ee37ffa..5d5c245c5 100644
--- a/spec/controllers/api/v1/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::AccountsController, type: :controller do
   render_views
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user) }
   let(:scopes) { '' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
@@ -69,7 +69,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #follow' do
     let(:scopes) { 'write:follows' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', locked: locked)).account }
+    let(:other_account) { Fabricate(:account, username: 'bob', locked: locked) }
 
     context do
       before do
@@ -150,7 +150,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #unfollow' do
     let(:scopes) { 'write:follows' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.follow!(other_account)
@@ -168,9 +168,29 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
     it_behaves_like 'forbidden for wrong scope', 'read:accounts'
   end
 
+  describe 'POST #remove_from_followers' do
+    let(:scopes) { 'write:follows' }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
+
+    before do
+      other_account.follow!(user.account)
+      post :remove_from_followers, params: { id: other_account.id }
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+
+    it 'removes the followed relation between user and target user' do
+      expect(user.account.followed_by?(other_account)).to be false
+    end
+
+    it_behaves_like 'forbidden for wrong scope', 'read:accounts'
+  end
+
   describe 'POST #block' do
     let(:scopes) { 'write:blocks' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.follow!(other_account)
@@ -194,7 +214,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #unblock' do
     let(:scopes) { 'write:blocks' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.block!(other_account)
@@ -214,7 +234,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #mute' do
     let(:scopes) { 'write:mutes' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.follow!(other_account)
@@ -242,7 +262,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #mute with notifications set to false' do
     let(:scopes) { 'write:mutes' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.follow!(other_account)
@@ -270,7 +290,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #mute with nonzero duration set' do
     let(:scopes) { 'write:mutes' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.follow!(other_account)
@@ -298,7 +318,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
 
   describe 'POST #unmute' do
     let(:scopes) { 'write:mutes' }
-    let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
+    let(:other_account) { Fabricate(:account, username: 'bob') }
 
     before do
       user.account.mute!(other_account)
diff --git a/spec/controllers/api/v1/admin/account_actions_controller_spec.rb b/spec/controllers/api/v1/admin/account_actions_controller_spec.rb
index a5a8f4bb0..601290b82 100644
--- a/spec/controllers/api/v1/admin/account_actions_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/account_actions_controller_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe Api::V1::Admin::AccountActionsController, type: :controller do
   render_views
 
   let(:role)   { 'moderator' }
-  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user, role: role) }
   let(:scopes) { 'admin:read admin:write' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-  let(:account) { Fabricate(:user).account }
+  let(:account) { Fabricate(:account) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/admin/accounts_controller_spec.rb b/spec/controllers/api/v1/admin/accounts_controller_spec.rb
index f6be35f7f..bf79ee520 100644
--- a/spec/controllers/api/v1/admin/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/accounts_controller_spec.rb
@@ -4,10 +4,10 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
   render_views
 
   let(:role)   { 'moderator' }
-  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user, role: role) }
   let(:scopes) { 'admin:read admin:write' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-  let(:account) { Fabricate(:user).account }
+  let(:account) { Fabricate(:account) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/admin/reports_controller_spec.rb b/spec/controllers/api/v1/admin/reports_controller_spec.rb
index 4ed3c5dc4..b6df53048 100644
--- a/spec/controllers/api/v1/admin/reports_controller_spec.rb
+++ b/spec/controllers/api/v1/admin/reports_controller_spec.rb
@@ -4,7 +4,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
   render_views
 
   let(:role)   { 'moderator' }
-  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user, role: role) }
   let(:scopes) { 'admin:read admin:write' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:report) { Fabricate(:report) }
diff --git a/spec/controllers/api/v1/blocks_controller_spec.rb b/spec/controllers/api/v1/blocks_controller_spec.rb
index 818f76c92..0e5c8296d 100644
--- a/spec/controllers/api/v1/blocks_controller_spec.rb
+++ b/spec/controllers/api/v1/blocks_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::BlocksController, type: :controller do
   render_views
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user) }
   let(:scopes) { 'read:blocks' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
diff --git a/spec/controllers/api/v1/conversations_controller_spec.rb b/spec/controllers/api/v1/conversations_controller_spec.rb
index 070f65061..5add7cf1d 100644
--- a/spec/controllers/api/v1/conversations_controller_spec.rb
+++ b/spec/controllers/api/v1/conversations_controller_spec.rb
@@ -3,9 +3,9 @@ require 'rails_helper'
 RSpec.describe Api::V1::ConversationsController, type: :controller do
   render_views
 
-  let!(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let!(:user) { Fabricate(:user, account_attributes: { username: 'alice' }) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-  let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
+  let(:other) { Fabricate(:user) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/domain_blocks_controller_spec.rb b/spec/controllers/api/v1/domain_blocks_controller_spec.rb
index 6a7a35c7a..d9dc1bdbf 100644
--- a/spec/controllers/api/v1/domain_blocks_controller_spec.rb
+++ b/spec/controllers/api/v1/domain_blocks_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::DomainBlocksController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
   before do
diff --git a/spec/controllers/api/v1/follow_requests_controller_spec.rb b/spec/controllers/api/v1/follow_requests_controller_spec.rb
index 1034faa32..856ba2a1c 100644
--- a/spec/controllers/api/v1/follow_requests_controller_spec.rb
+++ b/spec/controllers/api/v1/follow_requests_controller_spec.rb
@@ -3,9 +3,9 @@ require 'rails_helper'
 RSpec.describe Api::V1::FollowRequestsController, type: :controller do
   render_views
 
-  let(:user)     { Fabricate(:user, account: Fabricate(:account, username: 'alice', locked: true)) }
+  let(:user)     { Fabricate(:user, account_attributes: { locked: true }) }
   let(:token)    { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-  let(:follower) { Fabricate(:account, username: 'bob') }
+  let(:follower) { Fabricate(:account) }
 
   before do
     FollowService.new.call(follower, user.account)
diff --git a/spec/controllers/api/v1/instances_controller_spec.rb b/spec/controllers/api/v1/instances_controller_spec.rb
index 7397d25d6..842669d96 100644
--- a/spec/controllers/api/v1/instances_controller_spec.rb
+++ b/spec/controllers/api/v1/instances_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::InstancesController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id) }
 
   before do
diff --git a/spec/controllers/api/v1/lists/accounts_controller_spec.rb b/spec/controllers/api/v1/lists/accounts_controller_spec.rb
index 08c22de56..526d8b561 100644
--- a/spec/controllers/api/v1/lists/accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/lists/accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe Api::V1::Lists::AccountsController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let(:list)  { Fabricate(:list, account: user.account) }
 
diff --git a/spec/controllers/api/v1/lists_controller_spec.rb b/spec/controllers/api/v1/lists_controller_spec.rb
index e92213789..71a8094e6 100644
--- a/spec/controllers/api/v1/lists_controller_spec.rb
+++ b/spec/controllers/api/v1/lists_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::ListsController, type: :controller do
   render_views
 
-  let!(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let!(:user)  { Fabricate(:user) }
   let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
   let!(:list)  { Fabricate(:list, account: user.account) }
 
diff --git a/spec/controllers/api/v1/markers_controller_spec.rb b/spec/controllers/api/v1/markers_controller_spec.rb
index 556a75b9b..ba0f3c322 100644
--- a/spec/controllers/api/v1/markers_controller_spec.rb
+++ b/spec/controllers/api/v1/markers_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::MarkersController, type: :controller do
   render_views
 
-  let!(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let!(:user)  { Fabricate(:user) }
   let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses write:statuses') }
 
   before { allow(controller).to receive(:doorkeeper_token) { token } }
diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb
index 3eb015a1c..d8d732630 100644
--- a/spec/controllers/api/v1/media_controller_spec.rb
+++ b/spec/controllers/api/v1/media_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::MediaController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:media') }
 
   before do
diff --git a/spec/controllers/api/v1/mutes_controller_spec.rb b/spec/controllers/api/v1/mutes_controller_spec.rb
index a2b814a69..8176815d4 100644
--- a/spec/controllers/api/v1/mutes_controller_spec.rb
+++ b/spec/controllers/api/v1/mutes_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::MutesController, type: :controller do
   render_views
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user) }
   let(:scopes) { 'read:mutes' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb
index 5a0b24bbf..f8df6589f 100644
--- a/spec/controllers/api/v1/notifications_controller_spec.rb
+++ b/spec/controllers/api/v1/notifications_controller_spec.rb
@@ -3,10 +3,10 @@ require 'rails_helper'
 RSpec.describe Api::V1::NotificationsController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user, account_attributes: { username: 'alice' }) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
-  let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
-  let(:third) { Fabricate(:user, account: Fabricate(:account, username: 'carol')) }
+  let(:other) { Fabricate(:user) }
+  let(:third) { Fabricate(:user) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/polls/votes_controller_spec.rb b/spec/controllers/api/v1/polls/votes_controller_spec.rb
index 0ee3aa040..d7a9c1970 100644
--- a/spec/controllers/api/v1/polls/votes_controller_spec.rb
+++ b/spec/controllers/api/v1/polls/votes_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::Polls::VotesController, type: :controller do
   render_views
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user) }
   let(:scopes) { 'write:statuses' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
diff --git a/spec/controllers/api/v1/polls_controller_spec.rb b/spec/controllers/api/v1/polls_controller_spec.rb
index 851bccb7e..f0d9eaf92 100644
--- a/spec/controllers/api/v1/polls_controller_spec.rb
+++ b/spec/controllers/api/v1/polls_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::PollsController, type: :controller do
   render_views
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)   { Fabricate(:user) }
   let(:scopes) { 'read:statuses' }
   let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb
index a3596cf8a..a13de1370 100644
--- a/spec/controllers/api/v1/reports_controller_spec.rb
+++ b/spec/controllers/api/v1/reports_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::ReportsController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 
   before do
diff --git a/spec/controllers/api/v1/statuses/bookmarks_controller_spec.rb b/spec/controllers/api/v1/statuses/bookmarks_controller_spec.rb
index 7c75a4f73..46d7b6c0a 100644
--- a/spec/controllers/api/v1/statuses/bookmarks_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/bookmarks_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Statuses::BookmarksController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:bookmarks', application: app) }
 
diff --git a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
index f053ae573..439a4738d 100644
--- a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }
   let(:alice) { Fabricate(:account) }
diff --git a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb
index 4716ecae3..609957e3e 100644
--- a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Statuses::FavouritesController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:favourites', application: app) }
 
diff --git a/spec/controllers/api/v1/statuses/histories_controller_spec.rb b/spec/controllers/api/v1/statuses/histories_controller_spec.rb
new file mode 100644
index 000000000..00677f1d2
--- /dev/null
+++ b/spec/controllers/api/v1/statuses/histories_controller_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Api::V1::Statuses::HistoriesController do
+  render_views
+
+  let(:user)  { Fabricate(:user) }
+  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
+  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
+
+  context 'with an oauth token' do
+    before do
+      allow(controller).to receive(:doorkeeper_token) { token }
+    end
+
+    describe 'GET #show' do
+      let(:status) { Fabricate(:status, account: user.account) }
+
+      before do
+        get :show, params: { status_id: status.id }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
index 966398580..bffa9fe0d 100644
--- a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Statuses::MutesController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:mutes', application: app) }
 
diff --git a/spec/controllers/api/v1/statuses/pins_controller_spec.rb b/spec/controllers/api/v1/statuses/pins_controller_spec.rb
index 13405d285..8bdaf8b54 100644
--- a/spec/controllers/api/v1/statuses/pins_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/pins_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Statuses::PinsController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts', application: app) }
 
diff --git a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
index 60908b7b3..31320349d 100644
--- a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') }
   let(:alice) { Fabricate(:account) }
diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
index f1d3d949c..6eac02b23 100644
--- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Statuses::ReblogsController do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses', application: app) }
 
diff --git a/spec/controllers/api/v1/statuses/sources_controller_spec.rb b/spec/controllers/api/v1/statuses/sources_controller_spec.rb
new file mode 100644
index 000000000..fbe6fa0be
--- /dev/null
+++ b/spec/controllers/api/v1/statuses/sources_controller_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Api::V1::Statuses::SourcesController do
+  render_views
+
+  let(:user)  { Fabricate(:user) }
+  let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
+  let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }
+
+  context 'with an oauth token' do
+    before do
+      allow(controller).to receive(:doorkeeper_token) { token }
+    end
+
+    describe 'GET #show' do
+      let(:status) { Fabricate(:status, account: user.account) }
+
+      before do
+        get :show, params: { status_id: status.id }
+      end
+
+      it 'returns http success' do
+        expect(response).to have_http_status(200)
+      end
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb
index df8037038..2679ab017 100644
--- a/spec/controllers/api/v1/statuses_controller_spec.rb
+++ b/spec/controllers/api/v1/statuses_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 RSpec.describe Api::V1::StatusesController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:app)   { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: scopes) }
 
diff --git a/spec/controllers/api/v1/timelines/home_controller_spec.rb b/spec/controllers/api/v1/timelines/home_controller_spec.rb
index e953e4649..131c2d92f 100644
--- a/spec/controllers/api/v1/timelines/home_controller_spec.rb
+++ b/spec/controllers/api/v1/timelines/home_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Timelines::HomeController do
   render_views
 
-  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice'), current_sign_in_at: 1.day.ago) }
+  let(:user) { Fabricate(:user, current_sign_in_at: 1.day.ago) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/timelines/list_controller_spec.rb b/spec/controllers/api/v1/timelines/list_controller_spec.rb
index 45e4bf34c..526c66a05 100644
--- a/spec/controllers/api/v1/timelines/list_controller_spec.rb
+++ b/spec/controllers/api/v1/timelines/list_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Timelines::ListController do
   render_views
 
-  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user) { Fabricate(:user) }
   let(:list) { Fabricate(:list, account: user.account) }
 
   before do
@@ -30,7 +30,7 @@ describe Api::V1::Timelines::ListController do
   end
 
   context 'with the wrong user context' do
-    let(:other_user) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) }
+    let(:other_user) { Fabricate(:user) }
     let(:token)      { Fabricate(:accessible_access_token, resource_owner_id: other_user.id, scopes: 'read') }
 
     describe 'GET #show' do
diff --git a/spec/controllers/api/v1/timelines/public_controller_spec.rb b/spec/controllers/api/v1/timelines/public_controller_spec.rb
index b8e9d8674..0892d5db6 100644
--- a/spec/controllers/api/v1/timelines/public_controller_spec.rb
+++ b/spec/controllers/api/v1/timelines/public_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Timelines::PublicController do
   render_views
 
-  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user) { Fabricate(:user) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/timelines/tag_controller_spec.rb b/spec/controllers/api/v1/timelines/tag_controller_spec.rb
index f71ca2a39..718911083 100644
--- a/spec/controllers/api/v1/timelines/tag_controller_spec.rb
+++ b/spec/controllers/api/v1/timelines/tag_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 describe Api::V1::Timelines::TagController do
   render_views
 
-  let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user) { Fabricate(:user) }
 
   before do
     allow(controller).to receive(:doorkeeper_token) { token }
diff --git a/spec/controllers/api/v1/trends/tags_controller_spec.rb b/spec/controllers/api/v1/trends/tags_controller_spec.rb
new file mode 100644
index 000000000..e2e26dcab
--- /dev/null
+++ b/spec/controllers/api/v1/trends/tags_controller_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe Api::V1::Trends::TagsController, type: :controller do
+  render_views
+
+  describe 'GET #index' do
+    before do
+      trending_tags = double()
+
+      allow(trending_tags).to receive(:get).and_return(Fabricate.times(10, :tag))
+      allow(Trends).to receive(:tags).and_return(trending_tags)
+
+      get :index
+    end
+
+    it 'returns http success' do
+      expect(response).to have_http_status(200)
+    end
+  end
+end
diff --git a/spec/controllers/api/v1/trends_controller_spec.rb b/spec/controllers/api/v1/trends_controller_spec.rb
deleted file mode 100644
index 91e0d18fe..000000000
--- a/spec/controllers/api/v1/trends_controller_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe Api::V1::TrendsController, type: :controller do
-  render_views
-
-  describe 'GET #index' do
-    before do
-      allow(TrendingTags).to receive(:get).and_return(Fabricate.times(10, :tag))
-      get :index
-    end
-
-    it 'returns http success' do
-      expect(response).to have_http_status(200)
-    end
-  end
-end
diff --git a/spec/controllers/api/v2/search_controller_spec.rb b/spec/controllers/api/v2/search_controller_spec.rb
index 8ee8753de..fa20e1e51 100644
--- a/spec/controllers/api/v2/search_controller_spec.rb
+++ b/spec/controllers/api/v2/search_controller_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
 RSpec.describe Api::V2::SearchController, type: :controller do
   render_views
 
-  let(:user)  { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
+  let(:user)  { Fabricate(:user) }
   let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') }
 
   before do
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 881ecb124..a6a6871f7 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -49,7 +49,7 @@ describe ApplicationController, type: :controller do
 
     it 'returns account if signed in' do
       account = Fabricate(:account)
-      sign_in(Fabricate(:user, account: account))
+      sign_in(account.user)
       expect(controller.view_context.current_account).to eq account
     end
   end
@@ -168,13 +168,13 @@ describe ApplicationController, type: :controller do
     end
 
     it 'does nothing if user who signed in is not suspended' do
-      sign_in(Fabricate(:user, account: Fabricate(:account, suspended: false)))
+      sign_in(Fabricate(:account, suspended: false).user)
       get 'success'
       expect(response).to have_http_status(200)
     end
 
     it 'redirects to account status page' do
-      sign_in(Fabricate(:user, account: Fabricate(:account, suspended: true)))
+      sign_in(Fabricate(:account, suspended: true).user)
       get 'success'
       expect(response).to redirect_to(edit_user_registration_path)
     end
diff --git a/spec/controllers/auth/registrations_controller_spec.rb b/spec/controllers/auth/registrations_controller_spec.rb
index ccf304a93..0ebf6641f 100644
--- a/spec/controllers/auth/registrations_controller_spec.rb
+++ b/spec/controllers/auth/registrations_controller_spec.rb
@@ -228,7 +228,7 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
     end
 
     it 'does nothing if user already exists' do
-      Fabricate(:user, account: Fabricate(:account, username: 'test'))
+      Fabricate(:account, username: 'test')
       subject
     end
 
diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb
index d03ae51e8..64ec7b794 100644
--- a/spec/controllers/auth/sessions_controller_spec.rb
+++ b/spec/controllers/auth/sessions_controller_spec.rb
@@ -37,8 +37,11 @@ RSpec.describe Auth::SessionsController, type: :controller do
     end
 
     context 'with a suspended user' do
+      before do
+        user.account.suspend!
+      end
+
       it 'redirects to home after sign out' do
-        Fabricate(:account, user: user, suspended: true)
         sign_in(user, scope: :user)
         delete :destroy
 
@@ -78,8 +81,8 @@ RSpec.describe Auth::SessionsController, type: :controller do
       end
 
       context 'using a valid email and existing user' do
-        let(:user) do
-          account = Fabricate.build(:account, username: 'pam_user1')
+        let!(:user) do
+          account = Fabricate.build(:account, username: 'pam_user1', user: nil)
           account.save!(validate: false)
           user = Fabricate(:user, email: 'pam@example.com', password: nil, account: account, external: true)
           user
@@ -206,6 +209,38 @@ RSpec.describe Auth::SessionsController, type: :controller do
           end
         end
 
+        context 'using email and password after an unfinished log-in attempt to a 2FA-protected account' do
+          let!(:other_user) do
+            Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
+          end
+
+          before do
+            post :create, params: { user: { email: other_user.email, password: other_user.password } }
+            post :create, params: { user: { email: user.email, password: user.password } }
+          end
+
+          it 'renders two factor authentication page' do
+            expect(controller).to render_template("two_factor")
+            expect(controller).to render_template(partial: "_otp_authentication_form")
+          end
+        end
+
+        context 'using email and password after an unfinished log-in attempt with a sign-in token challenge' do
+          let!(:other_user) do
+            Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
+          end
+
+          before do
+            post :create, params: { user: { email: other_user.email, password: other_user.password } }
+            post :create, params: { user: { email: user.email, password: user.password } }
+          end
+
+          it 'renders two factor authentication page' do
+            expect(controller).to render_template("two_factor")
+            expect(controller).to render_template(partial: "_otp_authentication_form")
+          end
+        end
+
         context 'using upcase email and password' do
           before do
             post :create, params: { user: { email: user.email.upcase, password: user.password } }
@@ -231,6 +266,21 @@ RSpec.describe Auth::SessionsController, type: :controller do
           end
         end
 
+        context 'using a valid OTP, attempting to leverage previous half-login to bypass password auth' do
+          let!(:other_user) do
+            Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
+          end
+
+          before do
+            post :create, params: { user: { email: other_user.email, password: other_user.password } }
+            post :create, params: { user: { email: user.email, otp_attempt: user.current_otp } }, session: { attempt_user_updated_at: user.updated_at.to_s }
+          end
+
+          it "doesn't log the user in" do
+            expect(controller.current_user).to be_nil
+          end
+        end
+
         context 'when the server has an decryption error' do
           before do
             allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
@@ -353,7 +403,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
     end
 
     context 'when 2FA is disabled and IP is unfamiliar' do
-      let!(:user) { Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', current_sign_in_at: 3.weeks.ago, current_sign_in_ip: '0.0.0.0') }
+      let!(:user) { Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', current_sign_in_at: 3.weeks.ago) }
 
       before do
         request.remote_ip  = '10.10.10.10'
@@ -380,6 +430,52 @@ RSpec.describe Auth::SessionsController, type: :controller do
         end
       end
 
+      context 'using email and password after an unfinished log-in attempt to a 2FA-protected account' do
+        let!(:other_user) do
+          Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
+        end
+
+        before do
+          post :create, params: { user: { email: other_user.email, password: other_user.password } }
+          post :create, params: { user: { email: user.email, password: user.password } }
+        end
+
+        it 'renders sign in token authentication page' do
+          expect(controller).to render_template("sign_in_token")
+        end
+
+        it 'generates sign in token' do
+          expect(user.reload.sign_in_token).to_not be_nil
+        end
+
+        it 'sends sign in token e-mail' do
+          expect(UserMailer).to have_received(:sign_in_token)
+        end
+      end
+
+      context 'using email and password after an unfinished log-in attempt with a sign-in token challenge' do
+        let!(:other_user) do
+          Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
+        end
+
+        before do
+          post :create, params: { user: { email: other_user.email, password: other_user.password } }
+          post :create, params: { user: { email: user.email, password: user.password } }
+        end
+
+        it 'renders sign in token authentication page' do
+          expect(controller).to render_template("sign_in_token")
+        end
+
+        it 'generates sign in token' do
+          expect(user.reload.sign_in_token).to_not be_nil
+        end
+
+        it 'sends sign in token e-mail' do
+          expect(UserMailer).to have_received(:sign_in_token).with(user, any_args)
+        end
+      end
+
       context 'using a valid sign in token' do
         before do
           user.generate_sign_in_token && user.save
@@ -395,6 +491,22 @@ RSpec.describe Auth::SessionsController, type: :controller do
         end
       end
 
+      context 'using a valid sign in token, attempting to leverage previous half-login to bypass password auth' do
+        let!(:other_user) do
+          Fabricate(:user, email: 'z@y.com', password: 'abcdefgh', otp_required_for_login: false, current_sign_in_at: 1.month.ago)
+        end
+
+        before do
+          user.generate_sign_in_token && user.save
+          post :create, params: { user: { email: other_user.email, password: other_user.password } }
+          post :create, params: { user: { email: user.email, sign_in_token_attempt: user.sign_in_token } }, session: { attempt_user_updated_at: user.updated_at.to_s }
+        end
+
+        it "doesn't log the user in" do
+          expect(controller.current_user).to be_nil
+        end
+      end
+
       context 'using an invalid sign in token' do
         before do
           post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
@@ -410,4 +522,33 @@ RSpec.describe Auth::SessionsController, type: :controller do
       end
     end
   end
+
+  describe 'GET #webauthn_options' do
+    context 'with WebAuthn and OTP enabled as second factor' do
+      let(:domain) { "#{Rails.configuration.x.use_https ? 'https' : 'http' }://#{Rails.configuration.x.web_domain}" }
+
+      let(:fake_client) { WebAuthn::FakeClient.new(domain) }
+
+      let!(:user) do
+        Fabricate(:user, email: 'x@y.com', password: 'abcdefgh', otp_required_for_login: true, otp_secret: User.generate_otp_secret(32))
+      end
+
+      before do
+        user.update(webauthn_id: WebAuthn.generate_user_id)
+        public_key_credential = WebAuthn::Credential.from_create(fake_client.create)
+        user.webauthn_credentials.create(
+          nickname: 'SecurityKeyNickname',
+          external_id: public_key_credential.id,
+          public_key: public_key_credential.public_key,
+          sign_count: '1000'
+        )
+        post :create, params: { user: { email: user.email, password: user.password } }
+      end
+
+      it 'returns http success' do
+        get :webauthn_options
+        expect(response).to have_http_status :ok
+      end
+    end
+  end
 end
diff --git a/spec/controllers/authorize_interactions_controller_spec.rb b/spec/controllers/authorize_interactions_controller_spec.rb
index b4ce30cd7..99f3f6ffc 100644
--- a/spec/controllers/authorize_interactions_controller_spec.rb
+++ b/spec/controllers/authorize_interactions_controller_spec.rb
@@ -16,7 +16,6 @@ describe AuthorizeInteractionsController do
 
     describe 'when signed in' do
       let(:user) { Fabricate(:user) }
-      let(:account) { Fabricate(:account, user: user) }
 
       before do
         sign_in(user)
@@ -76,7 +75,7 @@ describe AuthorizeInteractionsController do
 
     describe 'when signed in' do
       let!(:user) { Fabricate(:user) }
-      let!(:account) { user.account }
+      let(:account) { user.account }
 
       before do
         sign_in(user)
diff --git a/spec/controllers/concerns/account_controller_concern_spec.rb b/spec/controllers/concerns/account_controller_concern_spec.rb
index 7ea214a7d..99975f4c4 100644
--- a/spec/controllers/concerns/account_controller_concern_spec.rb
+++ b/spec/controllers/concerns/account_controller_concern_spec.rb
@@ -11,13 +11,36 @@ describe ApplicationController, type: :controller do
     end
   end
 
+  around do |example|
+    registrations_mode = Setting.registrations_mode
+    example.run
+    Setting.registrations_mode = registrations_mode
+  end
+
   before do
     routes.draw { get 'success' => 'anonymous#success' }
   end
 
+  context 'when account is unconfirmed' do
+    it 'returns http not found' do
+      account = Fabricate(:user, confirmed_at: nil).account
+      get 'success', params: { account_username: account.username }
+      expect(response).to have_http_status(404)
+    end
+  end
+
+  context 'when account is not approved' do
+    it 'returns http not found' do
+      Setting.registrations_mode = 'approved'
+      account = Fabricate(:user, approved: false).account
+      get 'success', params: { account_username: account.username }
+      expect(response).to have_http_status(404)
+    end
+  end
+
   context 'when account is suspended' do
     it 'returns http gone' do
-      account = Fabricate(:account, suspended: true, user: Fabricate(:user))
+      account = Fabricate(:account, suspended: true)
       get 'success', params: { account_username: account.username }
       expect(response).to have_http_status(410)
     end
@@ -33,19 +56,19 @@ describe ApplicationController, type: :controller do
 
   context 'when account is not suspended' do
     it 'assigns @account' do
-      account = Fabricate(:account, user: Fabricate(:user))
+      account = Fabricate(:account)
       get 'success', params: { account_username: account.username }
       expect(assigns(:account)).to eq account
     end
 
     it 'sets link headers' do
-      account = Fabricate(:account, username: 'username', user: Fabricate(:user))
+      account = Fabricate(:account, username: 'username')
       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/jrd+json", <https://cb6e6126.ngrok.io/users/username>; rel="alternate"; type="application/activity+json"'
     end
 
     it 'returns http success' do
-      account = Fabricate(:account, user: Fabricate(:user))
+      account = Fabricate(:account)
       get 'success', params: { account_username: account.username }
       expect(response).to have_http_status(200)
     end
diff --git a/spec/controllers/concerns/accountable_concern_spec.rb b/spec/controllers/concerns/accountable_concern_spec.rb
index e3c06b494..5c5180bc2 100644
--- a/spec/controllers/concerns/accountable_concern_spec.rb
+++ b/spec/controllers/concerns/accountable_concern_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe AccountableConcern do
     end
   end
 
-  let(:user)   { Fabricate(:user, account: Fabricate(:account)) }
-  let(:target) { Fabricate(:user, account: Fabricate(:account)) }
-  let(:hoge)   { Hoge.new(user.account) }
+  let(:user)   { Fabricate(:account) }
+  let(:target) { Fabricate(:account) }
+  let(:hoge)   { Hoge.new(user) }
 
   describe '#log_action' do
     it 'creates Admin::ActionLog' do
       expect do
-        hoge.log_action(:create, target.account)
+        hoge.log_action(:create, target)
       end.to change { Admin::ActionLog.count }.by(1)
     end
   end
diff --git a/spec/controllers/follower_accounts_controller_spec.rb b/spec/controllers/follower_accounts_controller_spec.rb
index 006274169..eb095cf30 100644
--- a/spec/controllers/follower_accounts_controller_spec.rb
+++ b/spec/controllers/follower_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe FollowerAccountsController do
   render_views
 
-  let(:alice) { Fabricate(:user).account }
+  let(:alice) { Fabricate(:account) }
   let(:follower0) { Fabricate(:account) }
   let(:follower1) { Fabricate(:account) }
 
diff --git a/spec/controllers/following_accounts_controller_spec.rb b/spec/controllers/following_accounts_controller_spec.rb
index 7ec0e3d06..af5ce0787 100644
--- a/spec/controllers/following_accounts_controller_spec.rb
+++ b/spec/controllers/following_accounts_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
 describe FollowingAccountsController do
   render_views
 
-  let(:alice) { Fabricate(:user).account }
+  let(:alice) { Fabricate(:account) }
   let(:followee0) { Fabricate(:account) }
   let(:followee1) { Fabricate(:account) }
 
diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb
index 941f1dd91..70c5c42c5 100644
--- a/spec/controllers/home_controller_spec.rb
+++ b/spec/controllers/home_controller_spec.rb
@@ -8,8 +8,10 @@ RSpec.describe HomeController, type: :controller do
 
     context 'when not signed in' do
       context 'when requested path is tag timeline' do
-        before { @request.path = '/web/timelines/tag/name' }
-        it { is_expected.to redirect_to '/tags/name' }
+        it 'redirects to the tag\'s permalink' do
+          @request.path = '/web/timelines/tag/name'
+          is_expected.to redirect_to '/tags/name'
+        end
       end
 
       it 'redirects to about page' do
diff --git a/spec/controllers/media_controller_spec.rb b/spec/controllers/media_controller_spec.rb
index 2925aed59..efd15b5b4 100644
--- a/spec/controllers/media_controller_spec.rb
+++ b/spec/controllers/media_controller_spec.rb
@@ -6,33 +6,60 @@ describe MediaController do
   render_views
 
   describe '#show' do
-    it 'redirects to the file url when attached to a status' do
-      status = Fabricate(:status)
-      media_attachment = Fabricate(:media_attachment, status: status)
-      get :show, params: { id: media_attachment.to_param }
+    it 'raises when shortcode cant be found' do
+      get :show, params: { id: 'missing' }
 
-      expect(response).to redirect_to(media_attachment.file.url(:original))
+      expect(response).to have_http_status(404)
     end
 
-    it 'responds with missing when there is not an attached status' do
-      media_attachment = Fabricate(:media_attachment, status: nil)
-      get :show, params: { id: media_attachment.to_param }
+    context 'when the media attachment has a shortcode' do
+      it 'redirects to the file url when attached to a status' do
+        status = Fabricate(:status)
+        media_attachment = Fabricate(:media_attachment, status: status, shortcode: 'OI6IgDzG-nYTqvDQ994')
+        get :show, params: { id: media_attachment.to_param }
 
-      expect(response).to have_http_status(404)
-    end
+        expect(response).to redirect_to(media_attachment.file.url(:original))
+      end
 
-    it 'raises when shortcode cant be found' do
-      get :show, params: { id: 'missing' }
+      it 'responds with missing when there is not an attached status' do
+        media_attachment = Fabricate(:media_attachment, status: nil, shortcode: 'OI6IgDzG-nYTqvDQ994')
+        get :show, params: { id: media_attachment.to_param }
 
-      expect(response).to have_http_status(404)
+        expect(response).to have_http_status(404)
+      end
+
+      it 'raises when not permitted to view' do
+        status = Fabricate(:status, visibility: :direct)
+        media_attachment = Fabricate(:media_attachment, status: status, shortcode: 'OI6IgDzG-nYTqvDQ994')
+        get :show, params: { id: media_attachment.to_param }
+
+        expect(response).to have_http_status(404)
+      end
     end
 
-    it 'raises when not permitted to view' do
-      status = Fabricate(:status, visibility: :direct)
-      media_attachment = Fabricate(:media_attachment, status: status)
-      get :show, params: { id: media_attachment.to_param }
+    context 'when the media attachment has no shortcode' do
+      it 'redirects to the file url when attached to a status' do
+        status = Fabricate(:status)
+        media_attachment = Fabricate(:media_attachment, status: status)
+        get :show, params: { id: media_attachment.to_param }
 
-      expect(response).to have_http_status(404)
+        expect(response).to redirect_to(media_attachment.file.url(:original))
+      end
+
+      it 'responds with missing when there is not an attached status' do
+        media_attachment = Fabricate(:media_attachment, status: nil)
+        get :show, params: { id: media_attachment.to_param }
+
+        expect(response).to have_http_status(404)
+      end
+
+      it 'raises when not permitted to view' do
+        status = Fabricate(:status, visibility: :direct)
+        media_attachment = Fabricate(:media_attachment, status: status)
+        get :show, params: { id: media_attachment.to_param }
+
+        expect(response).to have_http_status(404)
+      end
     end
   end
 end
diff --git a/spec/controllers/settings/deletes_controller_spec.rb b/spec/controllers/settings/deletes_controller_spec.rb
index 8d5c4774f..cd36ecc35 100644
--- a/spec/controllers/settings/deletes_controller_spec.rb
+++ b/spec/controllers/settings/deletes_controller_spec.rb
@@ -17,7 +17,7 @@ describe Settings::DeletesController do
       end
 
       context 'when suspended' do
-        let(:user) { Fabricate(:user, account_attributes: { username: 'alice', suspended_at: Time.now.utc }) }
+        let(:user) { Fabricate(:user, account_attributes: { suspended_at: Time.now.utc }) }
 
         it 'returns http forbidden' do
           get :show
@@ -59,8 +59,12 @@ describe Settings::DeletesController do
           expect(user.account.reload).to be_suspended
         end
 
+        it 'does not create an email block' do
+          expect(CanonicalEmailBlock.block?(user.email)).to be false
+        end
+
         context 'when suspended' do
-          let(:user) { Fabricate(:user, account_attributes: { username: 'alice', suspended_at: Time.now.utc }) }
+          let(:user) { Fabricate(:user, account_attributes: { suspended_at: Time.now.utc }) }
 
           it 'returns http forbidden' do
             expect(response).to have_http_status(403)
diff --git a/spec/controllers/settings/identity_proofs_controller_spec.rb b/spec/controllers/settings/identity_proofs_controller_spec.rb
deleted file mode 100644
index 16f236227..000000000
--- a/spec/controllers/settings/identity_proofs_controller_spec.rb
+++ /dev/null
@@ -1,186 +0,0 @@
-require 'rails_helper'
-
-describe Settings::IdentityProofsController do
-  include RoutingHelper
-  render_views
-
-  let(:user) { Fabricate(:user) }
-  let(:valid_token) { '1'*66 }
-  let(:kbname) { 'kbuser' }
-  let(:provider) { 'keybase' }
-  let(:findable_id) { Faker::Number.number(digits: 5) }
-  let(:unfindable_id) { Faker::Number.number(digits: 5) }
-  let(:new_proof_params) do
-    { provider: provider, provider_username: kbname, token: valid_token, username: user.account.username }
-  end
-  let(:status_text) { "i just proved that i am also #{kbname} on #{provider}." }
-  let(:status_posting_params) do
-    { post_status: '0', status_text: status_text }
-  end
-  let(:postable_params) do
-    { account_identity_proof: new_proof_params.merge(status_posting_params) }
-  end
-
-  before do
-    allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:status) { { 'proof_valid' => true, 'proof_live' => true } }
-    sign_in user, scope: :user
-  end
-
-  describe 'new proof creation' do
-    context 'GET #new' do
-      before do
-        allow_any_instance_of(ProofProvider::Keybase::Badge).to receive(:avatar_url) { full_pack_url('media/images/void.png') }
-      end
-
-      context 'with all of the correct params' do
-        it 'renders the template' do
-          get :new, params: new_proof_params
-          expect(response).to render_template(:new)
-        end
-      end
-
-      context 'without any params' do
-        it 'redirects to :index' do
-          get :new, params: {}
-          expect(response).to redirect_to settings_identity_proofs_path
-        end
-      end
-
-      context 'with params to prove a different, not logged-in user' do
-        let(:wrong_user_params) { new_proof_params.merge(username: 'someone_else') }
-
-        it 'shows a helpful alert' do
-          get :new, params: wrong_user_params
-          expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.wrong_user', proving: 'someone_else', current: user.account.username)
-        end
-      end
-
-      context 'with params to prove the same username cased differently' do
-        let(:capitalized_username) { new_proof_params.merge(username: user.account.username.upcase) }
-
-        it 'renders the new template' do
-          get :new, params: capitalized_username
-          expect(response).to render_template(:new)
-        end
-      end
-    end
-
-    context 'POST #create' do
-      context 'when saving works' do
-        before do
-          allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
-          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
-          allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
-        end
-
-        it 'serializes a ProofProvider::Keybase::Worker' do
-          expect(ProofProvider::Keybase::Worker).to receive(:perform_async)
-          post :create, params: postable_params
-        end
-
-        it 'delegates redirection to the proof provider' do
-          expect_any_instance_of(AccountIdentityProof).to receive(:on_success_path)
-          post :create, params: postable_params
-          expect(response).to redirect_to root_url
-        end
-
-        it 'does not post a status' do
-          expect(PostStatusService).not_to receive(:new)
-          post :create, params: postable_params
-        end
-
-        context 'and the user has requested to post a status' do
-          let(:postable_params_with_status) do
-            postable_params.tap { |p| p[:account_identity_proof][:post_status] = '1' }
-          end
-
-          it 'posts a status' do
-            expect_any_instance_of(PostStatusService).to receive(:call).with(user.account, text: status_text)
-
-            post :create, params: postable_params_with_status
-          end
-        end
-      end
-
-      context 'when saving fails' do
-        before do
-          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { false }
-        end
-
-        it 'redirects to :index' do
-          post :create, params: postable_params
-          expect(response).to redirect_to settings_identity_proofs_path
-        end
-
-        it 'flashes a helpful message' do
-          post :create, params: postable_params
-          expect(flash[:alert]).to eq I18n.t('identity_proofs.errors.failed', provider: 'Keybase')
-        end
-      end
-
-      context 'it can also do an update if the provider and username match an existing proof' do
-        before do
-          allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
-          allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
-          Fabricate(:account_identity_proof, account: user.account, provider: provider, provider_username: kbname)
-          allow_any_instance_of(AccountIdentityProof).to receive(:on_success_path) { root_url }
-        end
-
-        it 'calls update with the new token' do
-          expect_any_instance_of(AccountIdentityProof).to receive(:save) do |proof|
-            expect(proof.token).to eq valid_token
-          end
-
-          post :create, params: postable_params
-        end
-      end
-    end
-  end
-
-  describe 'GET #index' do
-    context 'with no existing proofs' do
-      it 'shows the helpful explanation' do
-        get :index
-        expect(response.body).to match I18n.t('identity_proofs.explanation_html')
-      end
-    end
-
-    context 'with two proofs' do
-      before do
-        allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
-        @proof1 = Fabricate(:account_identity_proof, account: user.account)
-        @proof2 = Fabricate(:account_identity_proof, account: user.account)
-        allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
-        allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
-      end
-
-      it 'has the first proof username on the page' do
-        get :index
-        expect(response.body).to match /#{Regexp.quote(@proof1.provider_username)}/
-      end
-
-      it 'has the second proof username on the page' do
-        get :index
-        expect(response.body).to match /#{Regexp.quote(@proof2.provider_username)}/
-      end
-    end
-  end
-
-  describe 'DELETE #destroy' do
-    before do
-      allow_any_instance_of(ProofProvider::Keybase::Verifier).to receive(:valid?) { true }
-      @proof1 = Fabricate(:account_identity_proof, account: user.account)
-      allow_any_instance_of(AccountIdentityProof).to receive(:badge) { double(avatar_url: '', profile_url: '', proof_url: '') }
-      allow_any_instance_of(AccountIdentityProof).to receive(:refresh!) {}
-      delete :destroy, params: { id: @proof1.id }
-    end
-
-    it 'redirects to :index' do
-      expect(response).to redirect_to settings_identity_proofs_path
-    end
-
-    it 'removes the proof' do
-      expect(AccountIdentityProof.where(id: @proof1.id).count).to eq 0
-    end
-  end
-end
diff --git a/spec/controllers/settings/migrations_controller_spec.rb b/spec/controllers/settings/migrations_controller_spec.rb
index 048d9de8d..35c5747a0 100644
--- a/spec/controllers/settings/migrations_controller_spec.rb
+++ b/spec/controllers/settings/migrations_controller_spec.rb
@@ -19,8 +19,7 @@ describe Settings::MigrationsController do
     context 'when user is sign in' do
       subject { get :show }
 
-      let(:user) { Fabricate(:user, account: account) }
-      let(:account) { Fabricate(:account, moved_to_account: moved_to_account) }
+      let(:user) { Fabricate(:account, moved_to_account: moved_to_account).user }
 
       before { sign_in user, scope: :user }
 
diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb
index 1ac286254..ee3aec815 100644
--- a/spec/controllers/settings/profiles_controller_spec.rb
+++ b/spec/controllers/settings/profiles_controller_spec.rb
@@ -3,9 +3,11 @@ require 'rails_helper'
 RSpec.describe Settings::ProfilesController, type: :controller do
   render_views
 
+  let!(:user) { Fabricate(:user) }
+  let(:account) { user.account }
+
   before do
-    @user = Fabricate(:user)
-    sign_in @user, scope: :user
+    sign_in user, scope: :user
   end
 
   describe "GET #show" do
@@ -16,10 +18,12 @@ RSpec.describe Settings::ProfilesController, type: :controller do
   end
 
   describe 'PUT #update' do
+    before do
+      user.account.update(display_name: 'Old name')
+    end
+
     it 'updates the user profile' do
       allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
-      account = Fabricate(:account, user: @user, display_name: 'Old name')
-
       put :update, params: { account: { display_name: 'New name' } }
       expect(account.reload.display_name).to eq 'New name'
       expect(response).to redirect_to(settings_profile_path)
@@ -30,7 +34,6 @@ RSpec.describe Settings::ProfilesController, type: :controller do
   describe 'PUT #update with new profile image' do
     it 'updates profile image' do
       allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
-      account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
       expect(account.avatar.instance.avatar_file_name).to be_nil
 
       put :update, params: { account: { avatar: fixture_file_upload('avatar.gif', 'image/gif') } }
@@ -43,7 +46,6 @@ RSpec.describe Settings::ProfilesController, type: :controller do
   describe 'PUT #update with oversized image' do
     it 'gives the user an error message' do
       allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async)
-      account = Fabricate(:account, user: @user, display_name: 'AvatarTest')
       put :update, params: { account: { avatar: fixture_file_upload('4096x4097.png', 'image/png') } }
       expect(response.body).to include('images are not supported')
     end
diff --git a/spec/controllers/statuses_cleanup_controller_spec.rb b/spec/controllers/statuses_cleanup_controller_spec.rb
new file mode 100644
index 000000000..924709260
--- /dev/null
+++ b/spec/controllers/statuses_cleanup_controller_spec.rb
@@ -0,0 +1,27 @@
+require 'rails_helper'
+
+RSpec.describe StatusesCleanupController, type: :controller do
+  render_views
+
+  before do
+    @user = Fabricate(:user)
+    sign_in @user, scope: :user
+  end
+
+  describe "GET #show" do
+    it "returns http success" do
+      get :show
+      expect(response).to have_http_status(200)
+    end
+  end
+
+  describe 'PUT #update' do
+    it 'updates the account status cleanup policy' do
+      put :update, params: { account_statuses_cleanup_policy: { enabled: true, min_status_age: 2.weeks.seconds, keep_direct: false, keep_polls: true } }
+      expect(response).to redirect_to(statuses_cleanup_path)
+      expect(@user.account.statuses_cleanup_policy.enabled).to eq true
+      expect(@user.account.statuses_cleanup_policy.keep_direct).to eq false
+      expect(@user.account.statuses_cleanup_policy.keep_polls).to eq true
+    end
+  end
+end
diff --git a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb b/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
deleted file mode 100644
index 00f251c3c..000000000
--- a/spec/controllers/well_known/keybase_proof_config_controller_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'rails_helper'
-
-describe WellKnown::KeybaseProofConfigController, type: :controller do
-  render_views
-
-  describe 'GET #show' do
-    it 'renders json' do
-      get :show
-
-      expect(response).to have_http_status(200)
-      expect(response.media_type).to eq 'application/json'
-      expect { JSON.parse(response.body) }.not_to raise_exception
-    end
-  end
-end
diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb
index 1075456f3..8574d369d 100644
--- a/spec/controllers/well_known/webfinger_controller_spec.rb
+++ b/spec/controllers/well_known/webfinger_controller_spec.rb
@@ -24,6 +24,10 @@ describe WellKnown::WebfingerController, type: :controller do
         expect(response).to have_http_status(200)
       end
 
+      it 'does not set a Vary header' do
+        expect(response.headers['Vary']).to be_nil
+      end
+
       it 'returns application/jrd+json' do
         expect(response.media_type).to eq 'application/jrd+json'
       end