summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2024-02-28 17:18:31 +0100
committerClaire <claire.github-309c@sitedethib.com>2024-03-01 15:37:56 +0100
commit61bd11bacf1f254e20ba095331ca0ca19cf3a43a (patch)
tree47cb09bc5730e7cf9803853d472ed54b631d884f
parent7f84bbfd92377689f84121ec45c5b9d809d94cde (diff)
Add support for preview cards for local posts/accountsfeatures/local-preview-cards
-rw-r--r--app/models/local_preview_card.rb156
-rw-r--r--app/models/status.rb8
-rw-r--r--app/services/fetch_link_card_service.rb29
-rw-r--r--db/migrate/20240229163603_create_local_preview_cards.rb10
-rw-r--r--db/schema.rb16
5 files changed, 215 insertions, 4 deletions
diff --git a/app/models/local_preview_card.rb b/app/models/local_preview_card.rb
new file mode 100644
index 00000000000..e33789aed06
--- /dev/null
+++ b/app/models/local_preview_card.rb
@@ -0,0 +1,156 @@
+# frozen_string_literal: true
+
+# == Schema Information
+#
+# Table name: local_preview_cards
+#
+# id :bigint(8) not null, primary key
+# status_id :bigint(8) not null
+# target_status_id :bigint(8)
+# target_account_id :bigint(8)
+# created_at :datetime not null
+# updated_at :datetime not null
+#
+class LocalPreviewCard < ApplicationRecord
+ include ActionView::Helpers::NumberHelper
+ include InstanceHelper
+ include AccountsHelper
+ include StatusesHelper
+
+ belongs_to :status
+ belongs_to :target_status, class_name: 'Status', optional: true
+ belongs_to :target_account, class_name: 'Account', optional: true
+
+ def url
+ ActivityPub::TagManager.instance.url_for(object)
+ end
+
+ def embed_url
+ '' # TODO: audio/video uploads?
+ end
+
+ alias original_url url
+
+ def title
+ account = object.is_a?(Account) ? object : object.account
+ "#{display_name(account)} (#{acct(account)})"
+ end
+
+ def provider_name
+ site_title
+ end
+
+ def provider_url
+ ''
+ end
+
+ def author_name
+ ''
+ end
+
+ def author_url
+ ''
+ end
+
+ def description
+ if object.is_a?(Account)
+ account_description(object)
+ elsif object.is_a?(Status)
+ status_description(object)
+ end
+ end
+
+ def type
+ 'link'
+ end
+
+ def link_type
+ object.is_a?(Status) ? 'article' : 'unknown'
+ end
+
+ def html
+ ''
+ end
+
+ def published_at
+ nil
+ end
+
+ def max_score
+ nil
+ end
+
+ def max_score_at
+ nil
+ end
+
+ def trendable
+ false
+ end
+
+ def image_description
+ if object.is_a?(Account)
+ ''
+ elsif object.is_a?(Status)
+ status_media&.description.presence || ''
+ end
+ end
+
+ def width
+ if object.is_a?(Account)
+ 400
+ elsif object.is_a?(Status)
+ if status_media&.image? && status_media.file.meta.present?
+ status_media.file.meta.dig('original', 'width')
+ else
+ 0 # TODO
+ end
+ end
+ end
+
+ def height
+ if object.is_a?(Account)
+ 400
+ elsif object.is_a?(Status)
+ if status_media&.image? && status_media.file.meta.present?
+ status_media.file.meta.dig('original', 'height')
+ else
+ 0 # TODO
+ end
+ end
+ end
+
+ def blurhash
+ if object.is_a?(Account)
+ nil # TODO
+ elsif object.is_a?(Status)
+ status_media&.blurhash
+ end
+ end
+
+ def image
+ if object.is_a?(Account)
+ object.avatar
+ elsif object.is_a?(Status)
+ status_media&.thumbnail
+ end
+ end
+
+ def image?
+ image.present?
+ end
+
+ def language
+ nil # TODO
+ end
+
+ private
+
+ def object
+ target_status || target_account
+ end
+
+ def status_media
+ object.ordered_media_attachments.first
+ end
+end
diff --git a/app/models/status.rb b/app/models/status.rb
index 0ec69c8dd14..f855b6a4007 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -85,6 +85,7 @@ class Status < ApplicationRecord
has_and_belongs_to_many :tags
has_one :preview_cards_status, inverse_of: :status, dependent: :delete
+ has_one :local_preview_card, inverse_of: :status, dependent: :delete
has_one :notification, as: :activity, dependent: :destroy
has_one :status_stat, inverse_of: :status, dependent: nil
@@ -152,6 +153,7 @@ class Status < ApplicationRecord
:status_stat,
:tags,
:preloadable_poll,
+ :local_preview_card,
preview_cards_status: [:preview_card],
account: [:account_stat, user: :role],
active_mentions: { account: :account_stat },
@@ -162,6 +164,7 @@ class Status < ApplicationRecord
:conversation,
:status_stat,
:preloadable_poll,
+ :local_preview_card,
preview_cards_status: [:preview_card],
account: [:account_stat, user: :role],
active_mentions: { account: :account_stat },
@@ -229,10 +232,11 @@ class Status < ApplicationRecord
end
def preview_card
- preview_cards_status&.preview_card&.tap { |x| x.original_url = preview_cards_status.url }
+ local_preview_card || preview_cards_status&.preview_card&.tap { |x| x.original_url = preview_cards_status.url }
end
def reset_preview_card!
+ LocalPreviewCard.where(status_id: id).delete_all
PreviewCardsStatus.where(status_id: id).delete_all
end
@@ -251,7 +255,7 @@ class Status < ApplicationRecord
end
def with_preview_card?
- preview_cards_status.present?
+ local_preview_card.present? || preview_cards_status.present?
end
def with_poll?
diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb
index c6b600dd7cd..8e401e30418 100644
--- a/app/services/fetch_link_card_service.rb
+++ b/app/services/fetch_link_card_service.rb
@@ -23,6 +23,8 @@ class FetchLinkCardService < BaseService
@url = @original_url.to_s
+ return process_local_url if TagManager.instance.local_url?(@url)
+
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?
@@ -42,6 +44,24 @@ class FetchLinkCardService < BaseService
attempt_oembed || attempt_opengraph
end
+ def process_local_url
+ recognized_params = Rails.application.routes.recognize_path(@url)
+ return unless recognized_params[:action] == 'show'
+
+ @card = nil
+
+ case recognized_params[:controller]
+ when 'statuses'
+ status = Status.where(visibility: [:public, :unlisted]).find_by(id: recognized_params[:id])
+ @card = LocalPreviewCard.create(status: @status, target_status: status)
+ when 'accounts'
+ account = Account.find_local(recognized_params[:username])
+ @card = LocalPreviewCard.create(status: @status, target_account: account)
+ end
+
+ Rails.cache.delete(@status) if @card.present?
+ end
+
def html
return @html if defined?(@html)
@@ -85,7 +105,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/20240229163603_create_local_preview_cards.rb b/db/migrate/20240229163603_create_local_preview_cards.rb
new file mode 100644
index 00000000000..2e2b99e8fdc
--- /dev/null
+++ b/db/migrate/20240229163603_create_local_preview_cards.rb
@@ -0,0 +1,10 @@
+class CreateLocalPreviewCards < ActiveRecord::Migration[7.1]
+ def change
+ create_table :local_preview_cards do |t|
+ t.belongs_to :status, foreign_key: { on_delete: :cascade }, null: false
+ t.belongs_to :target_status, foreign_key: { on_delete: :cascade, to_table: :statuses }, null: true
+ t.belongs_to :target_account, foreign_key: { on_delete: :cascade, to_table: :accounts }, null: true
+ t.timestamps
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 50f4e7189df..af82639a98d 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_01_11_033014) do
+ActiveRecord::Schema[7.1].define(version: 2024_02_29_163603) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -594,6 +594,17 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_11_033014) do
t.index ["account_id"], name: "index_lists_on_account_id"
end
+ create_table "local_preview_cards", force: :cascade do |t|
+ t.bigint "status_id", null: false
+ t.bigint "target_status_id"
+ t.bigint "target_account_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["status_id"], name: "index_local_preview_cards_on_status_id"
+ t.index ["target_account_id"], name: "index_local_preview_cards_on_target_account_id"
+ t.index ["target_status_id"], name: "index_local_preview_cards_on_target_status_id"
+ end
+
create_table "login_activities", force: :cascade do |t|
t.bigint "user_id", null: false
t.string "authentication_method"
@@ -1246,6 +1257,9 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_11_033014) do
add_foreign_key "list_accounts", "follows", on_delete: :cascade
add_foreign_key "list_accounts", "lists", on_delete: :cascade
add_foreign_key "lists", "accounts", on_delete: :cascade
+ add_foreign_key "local_preview_cards", "accounts", column: "target_account_id", on_delete: :cascade
+ add_foreign_key "local_preview_cards", "statuses", column: "target_status_id", on_delete: :cascade
+ add_foreign_key "local_preview_cards", "statuses", on_delete: :cascade
add_foreign_key "login_activities", "users", on_delete: :cascade
add_foreign_key "markers", "users", on_delete: :cascade
add_foreign_key "media_attachments", "accounts", name: "fk_96dd81e81b", on_delete: :nullify