diff --git a/app/models/status.rb b/app/models/status.rb index e2b6f57bf..28c4e3b58 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -29,6 +29,7 @@ # edited_at :datetime # trendable :boolean # ordered_media_attachment_ids :bigint(8) is an Array +# quote_id :bigint(8) # class Status < ApplicationRecord @@ -63,6 +64,7 @@ class Status < ApplicationRecord belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true belongs_to :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, optional: true + belongs_to :quote, foreign_key: 'quote_id', class_name: 'Status', inverse_of: :quote, optional: true has_many :favourites, inverse_of: :status, dependent: :destroy has_many :bookmarks, inverse_of: :status, dependent: :destroy @@ -73,6 +75,7 @@ class Status < ApplicationRecord has_many :mentioned_accounts, through: :mentions, source: :account, class_name: 'Account' has_many :active_mentions, -> { active }, class_name: 'Mention', inverse_of: :status has_many :media_attachments, dependent: :nullify + has_many :quoted, foreign_key: 'quote_id', class_name: 'Status', inverse_of: :quote, dependent: :nullify # Those associations are used for the private search index has_many :local_mentioned, -> { merge(Account.local) }, through: :active_mentions, source: :account @@ -95,6 +98,7 @@ class Status < ApplicationRecord validates :reblog, uniqueness: { scope: :account }, if: :reblog? validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog? validates :content_type, inclusion: { in: %w(text/plain text/markdown text/html) }, allow_nil: true + validates :quote_visibility, inclusion: { in: %w(public unlisted) }, if: :quote? accepts_nested_attributes_for :poll @@ -107,6 +111,7 @@ class Status < ApplicationRecord scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') } scope :without_reblogs, -> { where(statuses: { reblog_of_id: nil }) } scope :with_public_visibility, -> { where(visibility: :public) } + scope :with_public_or_unlisted_visibility, -> { where(visibility: [:public, :unlisted]) } scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } @@ -170,6 +175,17 @@ class Status < ApplicationRecord account: [:account_stat, user: :role], active_mentions: { account: :account_stat }, ], + quote: [ + :application, + :tags, + :preview_cards, + :media_attachments, + :conversation, + :status_stat, + :preloadable_poll, + account: [:account_stat, :user], + active_mentions: { account: :account_stat }, + ], thread: { account: :account_stat } delegate :domain, to: :account, prefix: true @@ -204,6 +220,14 @@ class Status < ApplicationRecord !reblog_of_id.nil? end + def quote? + !quote_id.nil? && quote + end + + def quote_visibility + quote&.visibility + end + def within_realtime_window? created_at >= REAL_TIME_WINDOW.ago end @@ -272,7 +296,7 @@ class Status < ApplicationRecord fields = [spoiler_text, text] fields += preloadable_poll.options unless preloadable_poll.nil? - @emojis = CustomEmoji.from_text(fields.join(' '), account.domain) + @emojis = CustomEmoji.from_text(fields.join(' '), account.domain) + (quote? ? CustomEmoji.from_text([quote.spoiler_text, quote.text].join(' '), quote.account.domain) : []) end def ordered_media_attachments @@ -332,19 +356,19 @@ class Status < ApplicationRecord # _from_me part does not require any timeline filters query_from_me = where(account_id: account.id) - .where(Status.arel_table[:visibility].eq(3)) - .limit(limit) - .order('statuses.id DESC') + .where(Status.arel_table[:visibility].eq(3)) + .limit(limit) + .order('statuses.id DESC') # _to_me part requires mute and block filter. # FIXME: may we check mutes.hide_notifications? query_to_me = Status - .joins(:mentions) - .merge(Mention.where(account_id: account.id)) - .where(Status.arel_table[:visibility].eq(3)) - .limit(limit) - .order('mentions.status_id DESC') - .not_excluded_by_account(account) + .joins(:mentions) + .merge(Mention.where(account_id: account.id)) + .where(Status.arel_table[:visibility].eq(3)) + .limit(limit) + .order('mentions.status_id DESC') + .not_excluded_by_account(account) if max_id.present? query_from_me = query_from_me.where('statuses.id < ?', max_id)