Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app/models/status_reference.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
# Table name: status_references
#
# id :bigint(8) not null, primary key
# attribute_type :string
# created_at :datetime not null
# updated_at :datetime not null
# status_id :bigint(8) not null
Expand Down
87 changes: 20 additions & 67 deletions app/services/process_references_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ def call(status, reference_parameters, urls: nil, fetch_remote: true, no_fetch_u
@references_count = @status.reference_objects.count
build_references_diff

if @added_items.present? || @removed_items.present? || @changed_items.present?
if @added_status_ids.present? || @removed_status_ids.present?
StatusReference.transaction do
remove_old_references
add_references
change_reference_attributes

@status.save!
end
Expand Down Expand Up @@ -74,65 +73,32 @@ def self.call_service_without_error(status, reference_parameters, urls, quote: n
private

def build_old_references
@status.reference_objects.pluck(:target_status_id, :attribute_type).to_h
@status.reference_objects.pluck(:target_status_id)
end

def build_new_references
scan_text_and_quotes.tap do |status_id_to_attributes|
@reference_parameters.each do |status_id|
id_num = status_id.to_i
status_id_to_attributes[id_num] = 'BT' unless id_num.positive? && status_id_to_attributes.key?(id_num)
end
end
scan_text_and_quotes
end

def build_references_diff
olds = build_old_references
news = build_new_references

@changed_items = {}
@added_items = {}
@removed_items = {}

news.each_key do |status_id|
exist_attribute = olds[status_id]

@added_items[status_id] = news[status_id] if exist_attribute.nil?
@changed_items[status_id] = news[status_id] if olds.key?(status_id) && exist_attribute != news[status_id]
end

olds.each_key do |status_id|
new_attribute = news[status_id]

@removed_items[status_id] = olds[status_id] if new_attribute.nil?
end
@added_status_ids = (news - olds).uniq
@removed_status_ids = (olds - news).uniq
end

def scan_text_and_quotes
text = extract_status_plain_text(@status)
url_to_attributes = @urls.index_with('BT')
.merge(text.scan(REFURL_EXP).to_h { |result| [result[3], result[0]] })
@urls.index_with('BT')
.merge(text.scan(REFURL_EXP).to_h { |result| [result[3], result[0]] })

url_to_statuses = fetch_statuses(url_to_attributes.keys.uniq)
detected_urls = (@urls + text.scan(REFURL_EXP).pluck(3)).uniq
url_to_statuses = fetch_statuses(detected_urls)

@again = true if !@fetch_remote && url_to_statuses.values.any?(&:nil?)

url_to_statuses.keys.to_h do |url|
attribute = url_to_attributes[url] || 'BT'
status = url_to_statuses[url]

if status.present?
quote_attribute?(attribute)

[status.id, attribute]
else
[url, attribute]
end
end
end

def quote_attribute?(attribute)
%w(QT RE).include?(attribute)
url_to_statuses.keys.filter_map { |url| url_to_statuses[url]&.id }
end

def fetch_statuses(urls)
Expand All @@ -146,7 +112,7 @@ def fetch_statuses(urls)
def url_to_status(url)
status = ActivityPub::TagManager.instance.uri_to_resource(url, Status, url: true)
status ||= ResolveURLService.new.call(url, on_behalf_of: @status.account) unless bad_url_to_fetch?(url)
referrable?(status) ? status : nil
status
end

def bad_url_to_fetch?(url)
Expand All @@ -163,17 +129,16 @@ def referrable?(target_status)
end

def add_references
return if @added_items.empty?
return if @added_status_ids.empty?

@added_objects = []

statuses = Status.where(id: @added_items.keys).to_a
@added_items.each_key do |status_id|
statuses = Status.where(id: @added_status_ids).to_a
@added_status_ids.each do |status_id|
status = statuses.find { |s| s.id == status_id }
next if status.blank?
next if status.blank? || !referrable?(status)

attribute_type = @added_items[status_id]
@added_objects << @status.reference_objects.new(target_status: status, attribute_type: attribute_type)
@added_objects << @status.reference_objects.new(target_status: status)

status.increment_count!(:status_referred_by_count)
@references_count += 1
Expand All @@ -194,14 +159,14 @@ def create_notifications!
end

def remove_old_references
return if @removed_items.empty?
return if @removed_status_ids.empty?

@removed_objects = []

@status.reference_objects.where(target_status: @removed_items.keys).destroy_all
@status.reference_objects.where(target_status: @removed_status_ids).destroy_all

statuses = Status.where(id: @added_items.keys).to_a
@removed_items.each_key do |status_id|
statuses = Status.where(id: @removed_status_ids).to_a
@removed_status_ids.each do |status_id|
status = statuses.find { |s| s.id == status_id }
next if status.blank?

Expand All @@ -210,18 +175,6 @@ def remove_old_references
end
end

def change_reference_attributes
return if @changed_items.empty?

@changed_objects = []

@status.reference_objects.where(target_status: @changed_items.keys).find_each do |ref|
attribute_type = @changed_items[ref.target_status_id]

ref.update!(attribute_type: attribute_type)
end
end

def launch_worker
ProcessReferencesWorker.perform_async(@status.id, @reference_parameters, @urls, @no_fetch_urls)
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

class RemoveAttributeTypeFromStatusReferences < ActiveRecord::Migration[8.0]
def change
safety_assured do
remove_column :status_references, :attribute_type, :string
end
end
end
3 changes: 1 addition & 2 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2025_09_12_082651) do
ActiveRecord::Schema[8.0].define(version: 2025_09_22_234840) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql"

Expand Down Expand Up @@ -1451,7 +1451,6 @@
t.bigint "target_status_id", null: false
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.string "attribute_type"
t.index ["status_id"], name: "index_status_references_on_status_id"
t.index ["target_status_id"], name: "index_status_references_on_target_status_id"
end
Expand Down
1 change: 0 additions & 1 deletion spec/fabricators/status_reference_fabricator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
Fabricator(:status_reference) do
status { Fabricate.build(:status) }
target_status { Fabricate.build(:status) }
attribute_type 'BT'
end
31 changes: 12 additions & 19 deletions spec/services/process_references_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def notify?(target_status_id = nil)
target_status.account.user&.save

described_class.new.call(status, reference_parameters, urls: urls, fetch_remote: fetch_remote)
status.reference_objects.pluck(:target_status_id, :attribute_type)
status.reference_objects.pluck(:target_status_id)
end

let(:reference_parameters) { [] }
Expand All @@ -33,8 +33,7 @@ def notify?(target_status_id = nil)

it 'post status', :inline_jobs do
expect(subject.size).to eq 1
expect(subject.pluck(0)).to include target_status.id
expect(subject.pluck(1)).to include 'RT'
expect(subject).to include target_status.id
expect(notify?).to be true
end

Expand All @@ -50,8 +49,8 @@ def notify?(target_status_id = nil)

it 'post status', :inline_jobs do
expect(subject.size).to eq 2
expect(subject).to include [target_status.id, 'RT']
expect(subject).to include [target_status2.id, 'BT']
expect(subject).to include target_status.id
expect(subject).to include target_status2.id
expect(notify?).to be true
expect(notify?(target_status2.id)).to be true
end
Expand All @@ -63,8 +62,7 @@ def notify?(target_status_id = nil)

it 'post status', :inline_jobs do
expect(subject.size).to eq 1
expect(subject.pluck(0)).to include target_status.id
expect(subject.pluck(1)).to include 'RT'
expect(subject).to include target_status.id
expect(notify?).to be false
end
end
Expand All @@ -84,8 +82,7 @@ def notify?(target_status_id = nil)

it 'post status', :inline_jobs do
expect(subject.size).to eq 1
expect(subject.pluck(0)).to include target_status.id
expect(subject.pluck(1)).to include 'QT'
expect(subject).to include target_status.id

# it's not kmyblue legacy quote
expect(status.quote).to be_nil
Expand Down Expand Up @@ -116,8 +113,7 @@ def notify?(target_status_id = nil)

it 'post status', :inline_jobs do
expect(subject.size).to eq 1
expect(subject.pluck(0)).to include target_status.id
expect(subject.pluck(1)).to include 'RT'
expect(subject).to include target_status.id
expect(notify?).to be true
end
end
Expand Down Expand Up @@ -154,9 +150,8 @@ def notify?(target_status_id = nil)

it 'reference it', :inline_jobs do
expect(subject.size).to eq 1
expect(subject[0][1]).to eq 'BT'

status = Status.find_by(id: subject[0][0])
status = Status.find_by(id: subject[0])
expect(status).to_not be_nil
expect(status.url).to eq 'https://example.com/test_post'
end
Expand All @@ -165,7 +160,7 @@ def notify?(target_status_id = nil)
let(:fetch_remote) { false }

it 'reference it', :inline_jobs do
ids = subject.pluck(0)
ids = subject
expect(ids.size).to eq 1

status = Status.find_by(id: ids[0])
Expand All @@ -180,10 +175,9 @@ def notify?(target_status_id = nil)

it 'reference it', :inline_jobs do
expect(subject.size).to eq 2
expect(subject).to include [target_status.id, 'RT']
expect(subject.pluck(1)).to include 'BT'
expect(subject).to include target_status.id

status = Status.find_by(id: subject.pluck(0), uri: 'https://example.com/test_post')
status = Status.find_by(id: subject, uri: 'https://example.com/test_post')
expect(status).to_not be_nil
end
end
Expand Down Expand Up @@ -216,9 +210,8 @@ def notify?(target_status_id = nil)
shared_examples 'reference once' do |uri, url|
it 'reference it', :inline_jobs do
expect(subject.size).to eq 1
expect(subject[0][1]).to eq 'BT'

status = Status.find_by(id: subject[0][0])
status = Status.find_by(id: subject[0])
expect(status).to_not be_nil
expect(status.id).to eq remote_status.id
expect(status.uri).to eq uri
Expand Down