Rename :poll to :preloadable_poll and :owned_poll to :poll on Status (#10401)

Also, fix some n+1 queries

Resolve #10365
This commit is contained in:
Eugen Rochko 2019-03-28 04:44:59 +01:00 committed by GitHub
parent f46f67d984
commit f1bc90ab50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 45 additions and 43 deletions

View File

@ -105,8 +105,8 @@ module StreamEntriesHelper
end end
def poll_summary(status) def poll_summary(status)
return unless status.poll return unless status.preloadable_poll
status.poll.options.map { |o| "[ ] #{o}" }.join("\n") status.preloadable_poll.options.map { |o| "[ ] #{o}" }.join("\n")
end end
def status_description(status) def status_description(status)

View File

@ -68,7 +68,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
thread: replied_to_status, thread: replied_to_status,
conversation: conversation_from_uri(@object['conversation']), conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id), media_attachment_ids: process_attachments.take(4).map(&:id),
owned_poll: process_poll, poll: process_poll,
} }
end end
end end
@ -240,11 +240,11 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
end end
def poll_vote? def poll_vote?
return false if replied_to_status.nil? || replied_to_status.poll.nil? || !replied_to_status.local? || !replied_to_status.poll.options.include?(@object['name']) return false if replied_to_status.nil? || replied_to_status.preloadable_poll.nil? || !replied_to_status.local? || !replied_to_status.preloadable_poll.options.include?(@object['name'])
unless replied_to_status.poll.expired? unless replied_to_status.preloadable_poll.expired?
replied_to_status.poll.votes.create!(account: @account, choice: replied_to_status.poll.options.index(@object['name']), uri: @object['id']) replied_to_status.preloadable_poll.votes.create!(account: @account, choice: replied_to_status.preloadable_poll.options.index(@object['name']), uri: @object['id'])
ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.poll.hide_totals? ActivityPub::DistributePollUpdateWorker.perform_in(3.minutes, replied_to_status.id) unless replied_to_status.preloadable_poll.hide_totals?
end end
true true

View File

@ -23,8 +23,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
return reject_payload! if invalid_origin?(@object['id']) return reject_payload! if invalid_origin?(@object['id'])
status = Status.find_by(uri: object_uri, account_id: @account.id) status = Status.find_by(uri: object_uri, account_id: @account.id)
return if status.nil? || status.poll.nil? return if status.nil? || status.preloadable_poll.nil?
ActivityPub::ProcessPollService.new.call(status.poll, @object) ActivityPub::ProcessPollService.new.call(status.preloadable_poll, @object)
end end
end end

View File

@ -19,8 +19,8 @@ class Formatter
raw_content = status.text raw_content = status.text
if options[:inline_poll_options] && status.poll if options[:inline_poll_options] && status.preloadable_poll
raw_content = raw_content + "\n\n" + status.poll.options.map { |title| "[ ] #{title}" }.join("\n") raw_content = raw_content + "\n\n" + status.preloadable_poll.options.map { |title| "[ ] #{title}" }.join("\n")
end end
return '' if raw_content.blank? return '' if raw_content.blank?

View File

@ -25,7 +25,7 @@ class Notification < ApplicationRecord
poll: 'Poll', poll: 'Poll',
}.freeze }.freeze
STATUS_INCLUDES = [:account, :application, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :media_attachments, :tags, active_mentions: :account]].freeze STATUS_INCLUDES = [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account, reblog: [:account, :application, :preloadable_poll, :media_attachments, :tags, active_mentions: :account]].freeze
belongs_to :account, optional: true belongs_to :account, optional: true
belongs_to :from_account, class_name: 'Account', optional: true belongs_to :from_account, class_name: 'Account', optional: true

View File

@ -45,7 +45,7 @@ class Status < ApplicationRecord
belongs_to :account, inverse_of: :statuses belongs_to :account, inverse_of: :statuses
belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account', optional: true belongs_to :in_reply_to_account, foreign_key: 'in_reply_to_account_id', class_name: 'Account', optional: true
belongs_to :conversation, optional: true belongs_to :conversation, optional: true
belongs_to :poll, optional: true belongs_to :preloadable_poll, class_name: 'Poll', foreign_key: 'poll_id', optional: true
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies, optional: true 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 :reblog, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblogs, optional: true
@ -63,7 +63,7 @@ class Status < ApplicationRecord
has_one :notification, as: :activity, dependent: :destroy has_one :notification, as: :activity, dependent: :destroy
has_one :stream_entry, as: :activity, inverse_of: :status has_one :stream_entry, as: :activity, inverse_of: :status
has_one :status_stat, inverse_of: :status has_one :status_stat, inverse_of: :status
has_one :owned_poll, class_name: 'Poll', inverse_of: :status, dependent: :destroy has_one :poll, inverse_of: :status, dependent: :destroy
validates :uri, uniqueness: true, presence: true, unless: :local? validates :uri, uniqueness: true, presence: true, unless: :local?
validates :text, presence: true, unless: -> { with_media? || reblog? } validates :text, presence: true, unless: -> { with_media? || reblog? }
@ -72,7 +72,7 @@ class Status < ApplicationRecord
validates :reblog, uniqueness: { scope: :account }, if: :reblog? validates :reblog, uniqueness: { scope: :account }, if: :reblog?
validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog? validates :visibility, exclusion: { in: %w(direct limited) }, if: :reblog?
accepts_nested_attributes_for :owned_poll accepts_nested_attributes_for :poll
default_scope { recent } default_scope { recent }
@ -107,7 +107,7 @@ class Status < ApplicationRecord
:tags, :tags,
:preview_cards, :preview_cards,
:stream_entry, :stream_entry,
:poll, :preloadable_poll,
account: :account_stat, account: :account_stat,
active_mentions: { account: :account_stat }, active_mentions: { account: :account_stat },
reblog: [ reblog: [
@ -118,7 +118,7 @@ class Status < ApplicationRecord
:media_attachments, :media_attachments,
:conversation, :conversation,
:status_stat, :status_stat,
:poll, :preloadable_poll,
account: :account_stat, account: :account_stat,
active_mentions: { account: :account_stat }, active_mentions: { account: :account_stat },
], ],
@ -214,10 +214,11 @@ class Status < ApplicationRecord
def emojis def emojis
return @emojis if defined?(@emojis) return @emojis if defined?(@emojis)
fields = [spoiler_text, text]
fields += owned_poll.options unless owned_poll.nil? 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)
@emojis
end end
def mark_for_mass_destruction! def mark_for_mass_destruction!
@ -453,7 +454,7 @@ class Status < ApplicationRecord
end end
def set_poll_id def set_poll_id
update_column(:poll_id, owned_poll.id) unless owned_poll.nil? update_column(:poll_id, poll.id) unless poll.nil?
end end
def set_visibility def set_visibility

View File

@ -29,7 +29,7 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
end end
def type def type
object.poll ? 'Question' : 'Note' object.preloadable_poll ? 'Question' : 'Note'
end end
def summary def summary
@ -125,29 +125,29 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
end end
def poll_options def poll_options
object.poll.loaded_options object.preloadable_poll.loaded_options
end end
def poll_and_multiple? def poll_and_multiple?
object.poll&.multiple? object.preloadable_poll&.multiple?
end end
def poll_and_not_multiple? def poll_and_not_multiple?
object.poll && !object.poll.multiple? object.preloadable_poll && !object.preloadable_poll.multiple?
end end
def closed def closed
object.poll.expires_at.iso8601 object.preloadable_poll.expires_at.iso8601
end end
alias end_time closed alias end_time closed
def poll_and_expires? def poll_and_expires?
object.poll&.expires_at&.present? object.preloadable_poll&.expires_at&.present?
end end
def poll_and_expired? def poll_and_expired?
object.poll&.expired? object.preloadable_poll&.expired?
end end
class MediaAttachmentSerializer < ActivityPub::Serializer class MediaAttachmentSerializer < ActivityPub::Serializer

View File

@ -6,7 +6,7 @@ class ActivityPub::UpdatePollSerializer < ActivityPub::Serializer
has_one :object, serializer: ActivityPub::NoteSerializer has_one :object, serializer: ActivityPub::NoteSerializer
def id def id
[ActivityPub::TagManager.instance.uri_for(object), '#updates/', object.poll.updated_at.to_i].join [ActivityPub::TagManager.instance.uri_for(object), '#updates/', object.preloadable_poll.updated_at.to_i].join
end end
def type def type

View File

@ -21,7 +21,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
has_many :emojis, serializer: REST::CustomEmojiSerializer has_many :emojis, serializer: REST::CustomEmojiSerializer
has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer has_one :preview_card, key: :card, serializer: REST::PreviewCardSerializer
has_one :poll, serializer: REST::PollSerializer has_one :preloadable_poll, key: :poll, serializer: REST::PollSerializer
def id def id
object.id.to_s object.id.to_s

View File

@ -155,7 +155,7 @@ class PostStatusService < BaseService
text: @text, text: @text,
media_attachments: @media || [], media_attachments: @media || [],
thread: @in_reply_to, thread: @in_reply_to,
owned_poll_attributes: poll_attributes, poll_attributes: poll_attributes,
sensitive: (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?, sensitive: (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?,
spoiler_text: @options[:spoiler_text] || '', spoiler_text: @options[:spoiler_text] || '',
visibility: @visibility, visibility: @visibility,

View File

@ -22,9 +22,9 @@
%a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more')
.e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
- if status.poll - if status.preloadable_poll
= react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do
= render partial: 'stream_entries/poll', locals: { status: status, poll: status.poll, autoplay: autoplay } = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
- elsif !status.media_attachments.empty? - elsif !status.media_attachments.empty?
- if status.media_attachments.first.video? - if status.media_attachments.first.video?
- video = status.media_attachments.first - video = status.media_attachments.first

View File

@ -26,9 +26,9 @@
%a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more') %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more')
.e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) .e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }= Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay)
- if status.poll - if status.preloadable_poll
= react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do
= render partial: 'stream_entries/poll', locals: { status: status, poll: status.poll, autoplay: autoplay } = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay }
- elsif !status.media_attachments.empty? - elsif !status.media_attachments.empty?
- if status.media_attachments.first.video? - if status.media_attachments.first.video?
- video = status.media_attachments.first - video = status.media_attachments.first

View File

@ -9,7 +9,7 @@ class ActivityPub::DistributePollUpdateWorker
@status = Status.find(status_id) @status = Status.find(status_id)
@account = @status.account @account = @status.account
return unless @status.poll return unless @status.preloadable_poll
ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url| ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
[payload, @account.id, inbox_url] [payload, @account.id, inbox_url]
@ -29,7 +29,7 @@ class ActivityPub::DistributePollUpdateWorker
def inboxes def inboxes
return @inboxes if defined?(@inboxes) return @inboxes if defined?(@inboxes)
@inboxes = [@status.mentions, @status.reblogs, @status.poll.votes].flat_map do |relation| @inboxes = [@status.mentions, @status.reblogs, @status.preloadable_poll.votes].flat_map do |relation|
relation.includes(:account).map do |record| relation.includes(:account).map do |record|
record.account.preferred_inbox_url if !record.account.local? && record.account.activitypub? record.account.preferred_inbox_url if !record.account.local? && record.account.activitypub?
end end

View File

@ -2,8 +2,9 @@
en: en:
activerecord: activerecord:
attributes: attributes:
status: poll:
owned_poll: Poll expires_at: Deadline
options: Choices
errors: errors:
models: models:
account: account:

View File

@ -464,7 +464,7 @@ RSpec.describe ActivityPub::Activity::Create do
context 'when a vote to a local poll' do context 'when a vote to a local poll' do
let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) } let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) }
let!(:local_status) { Fabricate(:status, owned_poll: poll) } let!(:local_status) { Fabricate(:status, poll: poll) }
let(:object_json) do let(:object_json) do
{ {
@ -489,7 +489,7 @@ RSpec.describe ActivityPub::Activity::Create do
poll.save(validate: false) poll.save(validate: false)
poll poll
end end
let!(:local_status) { Fabricate(:status, owned_poll: poll) } let!(:local_status) { Fabricate(:status, poll: poll) }
let(:object_json) do let(:object_json) do
{ {