Change lists to be able to include accounts with pending follow requests (#19727)
parent
598e63dad2
commit
6693a4fe7c
|
@ -272,6 +272,7 @@ module AccountInteractions
|
||||||
|
|
||||||
def lists_for_local_distribution
|
def lists_for_local_distribution
|
||||||
lists.joins(account: :user)
|
lists.joins(account: :user)
|
||||||
|
.where.not(list_accounts: { follow_id: nil })
|
||||||
.where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
|
.where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ class FollowRequest < ApplicationRecord
|
||||||
validates :languages, language: true
|
validates :languages, language: true
|
||||||
|
|
||||||
def authorize!
|
def authorize!
|
||||||
account.follow!(target_account, reblogs: show_reblogs, notify: notify, languages: languages, uri: uri, bypass_limit: true)
|
follow = account.follow!(target_account, reblogs: show_reblogs, notify: notify, languages: languages, uri: uri, bypass_limit: true)
|
||||||
|
ListAccount.where(follow_request: self).update_all(follow_request_id: nil, follow_id: follow.id) # rubocop:disable Rails/SkipsModelValidations
|
||||||
MergeWorker.perform_async(target_account.id, account.id) if account.local?
|
MergeWorker.perform_async(target_account.id, account.id) if account.local?
|
||||||
destroy!
|
destroy!
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,12 +8,14 @@
|
||||||
# list_id :bigint(8) not null
|
# list_id :bigint(8) not null
|
||||||
# account_id :bigint(8) not null
|
# account_id :bigint(8) not null
|
||||||
# follow_id :bigint(8)
|
# follow_id :bigint(8)
|
||||||
|
# follow_request_id :bigint(8)
|
||||||
#
|
#
|
||||||
|
|
||||||
class ListAccount < ApplicationRecord
|
class ListAccount < ApplicationRecord
|
||||||
belongs_to :list
|
belongs_to :list
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
belongs_to :follow, optional: true
|
belongs_to :follow, optional: true
|
||||||
|
belongs_to :follow_request, optional: true
|
||||||
|
|
||||||
validates :account_id, uniqueness: { scope: :list_id }
|
validates :account_id, uniqueness: { scope: :list_id }
|
||||||
|
|
||||||
|
@ -22,6 +24,10 @@ class ListAccount < ApplicationRecord
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_follow
|
def set_follow
|
||||||
self.follow = Follow.find_by!(account_id: list.account_id, target_account_id: account.id) unless list.account_id == account.id
|
return if list.account_id == account.id
|
||||||
|
|
||||||
|
self.follow = Follow.find_by!(account_id: list.account_id, target_account_id: account.id)
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
self.follow_request = FollowRequest.find_by!(account_id: list.account_id, target_account_id: account.id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddFollowRequestIdToListAccounts < ActiveRecord::Migration[6.1]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
safety_assured { add_reference :list_accounts, :follow_request, foreign_key: { on_delete: :cascade }, index: false }
|
||||||
|
add_index :list_accounts, :follow_request_id, algorithm: :concurrently, where: 'follow_request_id IS NOT NULL'
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2023_03_30_140036) do
|
ActiveRecord::Schema.define(version: 2023_03_30_155710) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -554,8 +554,10 @@ ActiveRecord::Schema.define(version: 2023_03_30_140036) do
|
||||||
t.bigint "list_id", null: false
|
t.bigint "list_id", null: false
|
||||||
t.bigint "account_id", null: false
|
t.bigint "account_id", null: false
|
||||||
t.bigint "follow_id"
|
t.bigint "follow_id"
|
||||||
|
t.bigint "follow_request_id"
|
||||||
t.index ["account_id", "list_id"], name: "index_list_accounts_on_account_id_and_list_id", unique: true
|
t.index ["account_id", "list_id"], name: "index_list_accounts_on_account_id_and_list_id", unique: true
|
||||||
t.index ["follow_id"], name: "index_list_accounts_on_follow_id", where: "(follow_id IS NOT NULL)"
|
t.index ["follow_id"], name: "index_list_accounts_on_follow_id", where: "(follow_id IS NOT NULL)"
|
||||||
|
t.index ["follow_request_id"], name: "index_list_accounts_on_follow_request_id", where: "(follow_request_id IS NOT NULL)"
|
||||||
t.index ["list_id", "account_id"], name: "index_list_accounts_on_list_id_and_account_id"
|
t.index ["list_id", "account_id"], name: "index_list_accounts_on_list_id_and_account_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1198,6 +1200,7 @@ ActiveRecord::Schema.define(version: 2023_03_30_140036) do
|
||||||
add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade
|
add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade
|
||||||
add_foreign_key "invites", "users", on_delete: :cascade
|
add_foreign_key "invites", "users", on_delete: :cascade
|
||||||
add_foreign_key "list_accounts", "accounts", on_delete: :cascade
|
add_foreign_key "list_accounts", "accounts", on_delete: :cascade
|
||||||
|
add_foreign_key "list_accounts", "follow_requests", on_delete: :cascade
|
||||||
add_foreign_key "list_accounts", "follows", on_delete: :cascade
|
add_foreign_key "list_accounts", "follows", on_delete: :cascade
|
||||||
add_foreign_key "list_accounts", "lists", on_delete: :cascade
|
add_foreign_key "list_accounts", "lists", on_delete: :cascade
|
||||||
add_foreign_key "lists", "accounts", on_delete: :cascade
|
add_foreign_key "lists", "accounts", on_delete: :cascade
|
||||||
|
|
|
@ -29,6 +29,7 @@ describe Api::V1::Lists::AccountsController do
|
||||||
let(:scopes) { 'write:lists' }
|
let(:scopes) { 'write:lists' }
|
||||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||||
|
|
||||||
|
context 'when the added account is followed' do
|
||||||
before do
|
before do
|
||||||
user.account.follow!(bob)
|
user.account.follow!(bob)
|
||||||
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||||
|
@ -43,6 +44,36 @@ describe Api::V1::Lists::AccountsController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the added account has been sent a follow request' do
|
||||||
|
before do
|
||||||
|
user.account.follow_requests.create!(target_account: bob)
|
||||||
|
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http success' do
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds account to the list' do
|
||||||
|
expect(list.accounts.include?(bob)).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the added account is not followed' do
|
||||||
|
before do
|
||||||
|
post :create, params: { list_id: list.id, account_ids: [bob.id] }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns http not found' do
|
||||||
|
expect(response).to have_http_status(404)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not add the account to the list' do
|
||||||
|
expect(list.accounts.include?(bob)).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'DELETE #destroy' do
|
describe 'DELETE #destroy' do
|
||||||
let(:scopes) { 'write:lists' }
|
let(:scopes) { 'write:lists' }
|
||||||
|
|
||||||
|
|
|
@ -683,4 +683,28 @@ describe AccountInteractions do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#lists_for_local_distribution' do
|
||||||
|
let!(:inactive_follower_user) { Fabricate(:user, current_sign_in_at: 5.years.ago) }
|
||||||
|
let!(:follower_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
|
||||||
|
let!(:follow_request_user) { Fabricate(:user, current_sign_in_at: Time.now.utc) }
|
||||||
|
|
||||||
|
let!(:inactive_follower_list) { Fabricate(:list, account: inactive_follower_user.account) }
|
||||||
|
let!(:follower_list) { Fabricate(:list, account: follower_user.account) }
|
||||||
|
let!(:follow_request_list) { Fabricate(:list, account: follow_request_user.account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
inactive_follower_user.account.follow!(account)
|
||||||
|
follower_user.account.follow!(account)
|
||||||
|
follow_request_user.account.follow_requests.create!(target_account: account)
|
||||||
|
|
||||||
|
inactive_follower_list.accounts << account
|
||||||
|
follower_list.accounts << account
|
||||||
|
follow_request_list.accounts << account
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'includes only the list from the active follower' do
|
||||||
|
expect(account.lists_for_local_distribution.to_a).to eq [follower_list]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,12 +4,26 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe FollowRequest, type: :model do
|
RSpec.describe FollowRequest, type: :model do
|
||||||
describe '#authorize!' do
|
describe '#authorize!' do
|
||||||
let(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
|
let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
|
||||||
let(:account) { Fabricate(:account) }
|
let(:account) { Fabricate(:account) }
|
||||||
let(:target_account) { Fabricate(:account) }
|
let(:target_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
context 'when the to-be-followed person has been added to a list' do
|
||||||
|
let!(:list) { Fabricate(:list, account: account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
list.accounts << target_account
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the ListAccount' do
|
||||||
|
expect { follow_request.authorize! }.to change { [list.list_accounts.first.follow_request_id, list.list_accounts.first.follow_id] }.from([follow_request.id, nil]).to([nil, anything])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do
|
it 'calls Account#follow!, MergeWorker.perform_async, and #destroy!' do
|
||||||
expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true)
|
expect(account).to receive(:follow!).with(target_account, reblogs: true, notify: false, uri: follow_request.uri, languages: nil, bypass_limit: true) do
|
||||||
|
account.active_relationships.create!(target_account: target_account)
|
||||||
|
end
|
||||||
expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id)
|
expect(MergeWorker).to receive(:perform_async).with(target_account.id, account.id)
|
||||||
expect(follow_request).to receive(:destroy!)
|
expect(follow_request).to receive(:destroy!)
|
||||||
follow_request.authorize!
|
follow_request.authorize!
|
||||||
|
@ -29,4 +43,22 @@ RSpec.describe FollowRequest, type: :model do
|
||||||
expect(follow_request.account.muting_reblogs?(target)).to be true
|
expect(follow_request.account.muting_reblogs?(target)).to be true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#reject!' do
|
||||||
|
let!(:follow_request) { Fabricate(:follow_request, account: account, target_account: target_account) }
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
let(:target_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
context 'when the to-be-followed person has been added to a list' do
|
||||||
|
let!(:list) { Fabricate(:list, account: account) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
list.accounts << target_account
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deletes the ListAccount record' do
|
||||||
|
expect { follow_request.reject! }.to change { list.accounts.count }.from(1).to(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue