discourse/app/models/quoted_post.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

96 lines
3.0 KiB
Ruby

# frozen_string_literal: true
class QuotedPost < ActiveRecord::Base
belongs_to :post
belongs_to :quoted_post, class_name: 'Post'
# NOTE we already have a path that does this for topic links,
# however topic links exclude quotes and links within a topic
# we are double parsing this fragment, this may be worth optimising later
def self.extract_from(post)
doc = Nokogiri::HTML.fragment(post.cooked)
uniq = {}
doc.css("aside.quote[data-topic]").each do |a|
topic_id = a['data-topic'].to_i
post_number = a['data-post'].to_i
next if topic_id == 0 || post_number == 0
next if uniq[[topic_id, post_number]]
next if post.topic_id == topic_id && post.post_number == post_number
uniq[[topic_id, post_number]] = true
end
if uniq.length == 0
DB.exec("DELETE FROM quoted_posts WHERE post_id = :post_id", post_id: post.id)
else
args = {
post_id: post.id,
topic_ids: uniq.keys.map(&:first),
post_numbers: uniq.keys.map(&:second)
}
DB.exec(<<~SQL, args)
INSERT INTO quoted_posts (post_id, quoted_post_id, created_at, updated_at)
SELECT :post_id, p.id, current_timestamp, current_timestamp
FROM posts p
JOIN (
SELECT
unnest(ARRAY[:topic_ids]) topic_id,
unnest(ARRAY[:post_numbers]) post_number
) X ON X.topic_id = p.topic_id AND X.post_number = p.post_number
LEFT JOIN quoted_posts q on q.post_id = :post_id AND q.quoted_post_id = p.id
WHERE q.id IS NULL
SQL
DB.exec(<<~SQL, args)
DELETE FROM quoted_posts
WHERE post_id = :post_id
AND id IN (
SELECT q1.id FROM quoted_posts q1
LEFT JOIN posts p1 ON p1.id = q1.quoted_post_id
LEFT JOIN (
SELECT
unnest(ARRAY[:topic_ids]) topic_id,
unnest(ARRAY[:post_numbers]) post_number
) X on X.topic_id = p1.topic_id AND X.post_number = p1.post_number
WHERE q1.post_id = :post_id AND X.topic_id IS NULL
)
SQL
end
# simplest place to add this code
reply_quoted = false
if post.reply_to_post_number
reply_post_id = Post.where(topic_id: post.topic_id, post_number: post.reply_to_post_number).pluck(:id).first
reply_quoted = reply_post_id.present? && QuotedPost.where(post_id: post.id, quoted_post_id: reply_post_id).count > 0
end
if reply_quoted != post.reply_quoted
post.update_columns(reply_quoted: reply_quoted)
end
end
end
# == Schema Information
#
# Table name: quoted_posts
#
# id :integer not null, primary key
# post_id :integer not null
# quoted_post_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_quoted_posts_on_post_id_and_quoted_post_id (post_id,quoted_post_id) UNIQUE
# index_quoted_posts_on_quoted_post_id_and_post_id (quoted_post_id,post_id) UNIQUE
#