diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index 9fe02bd1681..d782184da0b 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -32,6 +32,8 @@ # link_type :integer # published_at :datetime # image_description :string default(""), not null +# target_status_id :bigint(8) +# target_account_id :bigint(8) # class PreviewCard < ApplicationRecord @@ -50,6 +52,9 @@ class PreviewCard < ApplicationRecord enum :type, { link: 0, photo: 1, video: 2, rich: 3 } enum :link_type, { unknown: 0, article: 1 } + belongs_to :target_status, class_name: 'Status', optional: true, dependent: :destroy + belongs_to :target_account, class_name: 'Account', optional: true, dependent: :destroy + has_many :preview_cards_statuses, dependent: :delete_all, inverse_of: :preview_card has_many :statuses, through: :preview_cards_statuses diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index c6b600dd7cd..03a8b20015d 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -26,6 +26,7 @@ class FetchLinkCardService < BaseService with_redis_lock("fetch:#{@original_url}") do @card = PreviewCard.find_by(url: @url) process_url if @card.nil? || @card.updated_at <= 2.weeks.ago || @card.missing_image? + attach_local_resource_to_card! end attach_card if @card&.persisted? @@ -60,6 +61,22 @@ class FetchLinkCardService < BaseService end end + def attach_local_resource_to_card! + return if @card.nil? || @card.target_account_id.present? || @card.target_status_id.present? || !TagManager.instance.local_url?(@card.url) + + recognized_params = Rails.application.routes.recognize_path(@card.url) + return if recognized_params[:action] != 'show' + + case recognized_params[:controller] + when 'accounts' + account = Account.find_local(recognized_params[:username]) + @card.update!(target_account: account) + when 'statuses' + status = Status.find_by(id: recognized_params[:id]) + @card.update!(target_status: status) + end + end + def attach_card with_redis_lock("attach_card:#{@status.id}") do return if @status.with_preview_card? @@ -85,7 +102,14 @@ class FetchLinkCardService < BaseService def bad_url?(uri) # Avoid local instance URLs and invalid URLs - uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) + uri.host.blank? || bad_local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) + end + + def bad_local_url?(uri) + return false unless TagManager.instance.local_url?(uri.to_s) + + recognized_params = Rails.application.routes.recognize_path(uri) + recognized_params[:action] != 'show' || %w(accounts statuses).exclude?(recognized_params[:controller]) end def mention_link?(anchor) diff --git a/db/migrate/20240326155335_add_target_status_id_to_preview_cards.rb b/db/migrate/20240326155335_add_target_status_id_to_preview_cards.rb new file mode 100644 index 00000000000..1ce7eb0b21a --- /dev/null +++ b/db/migrate/20240326155335_add_target_status_id_to_preview_cards.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddTargetStatusIdToPreviewCards < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + add_belongs_to :preview_cards, :target_status, null: true, index: { algorithm: :concurrently, where: 'target_status_id IS NOT NULL' } + end +end diff --git a/db/migrate/20240326160308_add_target_status_foreign_key_to_preview_cards.rb b/db/migrate/20240326160308_add_target_status_foreign_key_to_preview_cards.rb new file mode 100644 index 00000000000..302bd92a532 --- /dev/null +++ b/db/migrate/20240326160308_add_target_status_foreign_key_to_preview_cards.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddTargetStatusForeignKeyToPreviewCards < ActiveRecord::Migration[7.1] + def change + add_foreign_key :preview_cards, :statuses, column: :target_status_id, on_delete: :cascade, validate: false + end +end diff --git a/db/migrate/20240326160903_validate_target_status_foreign_key_on_preview_cards.rb b/db/migrate/20240326160903_validate_target_status_foreign_key_on_preview_cards.rb new file mode 100644 index 00000000000..a9369da370d --- /dev/null +++ b/db/migrate/20240326160903_validate_target_status_foreign_key_on_preview_cards.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ValidateTargetStatusForeignKeyOnPreviewCards < ActiveRecord::Migration[7.1] + def change + validate_foreign_key :preview_cards, column: :target_status_id + end +end diff --git a/db/migrate/20240326161252_add_target_account_id_to_preview_cards.rb b/db/migrate/20240326161252_add_target_account_id_to_preview_cards.rb new file mode 100644 index 00000000000..e8a2340f3ef --- /dev/null +++ b/db/migrate/20240326161252_add_target_account_id_to_preview_cards.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddTargetAccountIdToPreviewCards < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + add_belongs_to :preview_cards, :target_account, null: true, index: { algorithm: :concurrently, where: 'target_account_id IS NOT NULL' } + end +end diff --git a/db/migrate/20240326161607_add_target_account_foreign_key_to_preview_cards.rb b/db/migrate/20240326161607_add_target_account_foreign_key_to_preview_cards.rb new file mode 100644 index 00000000000..cf45f3989dc --- /dev/null +++ b/db/migrate/20240326161607_add_target_account_foreign_key_to_preview_cards.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddTargetAccountForeignKeyToPreviewCards < ActiveRecord::Migration[7.1] + def change + add_foreign_key :preview_cards, :accounts, column: :target_account_id, on_delete: :cascade, validate: false + end +end diff --git a/db/migrate/20240326161740_validate_target_account_foreign_key_on_preview_cards.rb b/db/migrate/20240326161740_validate_target_account_foreign_key_on_preview_cards.rb new file mode 100644 index 00000000000..a5d7ca75d48 --- /dev/null +++ b/db/migrate/20240326161740_validate_target_account_foreign_key_on_preview_cards.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ValidateTargetAccountForeignKeyOnPreviewCards < ActiveRecord::Migration[7.1] + def change + validate_foreign_key :preview_cards, column: :target_account_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 27c486487d8..c95401dcf9d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do +ActiveRecord::Schema[7.1].define(version: 2024_03_26_161740) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -874,6 +874,10 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do t.integer "link_type" t.datetime "published_at" t.string "image_description", default: "", null: false + t.bigint "target_status_id" + t.bigint "target_account_id" + t.index ["target_account_id"], name: "index_preview_cards_on_target_account_id", where: "(target_account_id IS NOT NULL)" + t.index ["target_status_id"], name: "index_preview_cards_on_target_status_id", where: "(target_status_id IS NOT NULL)" t.index ["url"], name: "index_preview_cards_on_url", unique: true end @@ -1347,6 +1351,8 @@ ActiveRecord::Schema[7.1].define(version: 2024_03_22_161611) do add_foreign_key "polls", "accounts", on_delete: :cascade add_foreign_key "polls", "statuses", on_delete: :cascade add_foreign_key "preview_card_trends", "preview_cards", on_delete: :cascade + add_foreign_key "preview_cards", "accounts", column: "target_account_id", on_delete: :cascade + add_foreign_key "preview_cards", "statuses", column: "target_status_id", on_delete: :cascade add_foreign_key "report_notes", "accounts", on_delete: :cascade add_foreign_key "report_notes", "reports", on_delete: :cascade add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", name: "fk_bca45b75fd", on_delete: :nullify