FIX: First Quote badge bust

Feature: track quoted posts
This commit is contained in:
Sam 2014-07-15 17:47:24 +10:00
parent 4c25fedf70
commit 2d0def9940
8 changed files with 141 additions and 9 deletions

View File

@ -123,6 +123,7 @@ class PostsController < ApplicationController
revisor = PostRevisor.new(post)
if revisor.revise!(current_user, params[:post][:raw], edit_reason: params[:post][:edit_reason])
TopicLink.extract_from(post)
QuotedPost.extract_from(post)
end
if post.errors.present?

View File

@ -45,17 +45,16 @@ SQL
SQL
FirstQuote = <<SQL
SELECT l.user_id, l.post_id, l.created_at granted_at
SELECT ids.user_id, q.post_id, q.created_at granted_at
FROM
(
SELECT MIN(l1.id) id
FROM topic_links l1
JOIN badge_posts p1 ON p1.id = l1.post_id
JOIN badge_posts p2 ON p2.id = l1.link_post_id
WHERE NOT reflection AND quote
GROUP BY l1.user_id
SELECT p1.user_id, MIN(q1.id) id
FROM quoted_posts q1
JOIN badge_posts p1 ON p1.id = q1.post_id
JOIN badge_posts p2 ON p2.id = q1.quoted_post_id
GROUP BY p1.user_id
) ids
JOIN topic_links l ON l.id = ids.id
JOIN quoted_posts q ON q.id = ids.id
SQL
FirstLink = <<SQL

View File

@ -93,6 +93,7 @@ class Post < ActiveRecord::Base
super
update_flagged_posts_count
TopicLink.extract_from(self)
QuotedPost.extract_from(self)
if topic && topic.category_id && topic.category
topic.category.update_latest
end
@ -336,7 +337,9 @@ class Post < ActiveRecord::Base
update_columns(cooked: new_cooked, baked_at: Time.new, baked_version: BAKED_VERSION)
# Extracts urls from the body
TopicLink.extract_from self
TopicLink.extract_from(self)
QuotedPost.extract_from(self)
# make sure we trigger the post process
trigger_post_process(true)

46
app/models/quoted_post.rb Normal file
View File

@ -0,0 +1,46 @@
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 = {}
ids = []
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]]
uniq[[topic_id,post_number]] = true
# It would be so much nicer if we used post_id in quotes
results = exec_sql "INSERT INTO quoted_posts(post_id, quoted_post_id, created_at, updated_at)
SELECT :post_id, id, current_timestamp, current_timestamp
FROM posts
WHERE post_number = :post_number AND
topic_id = :topic_id
RETURNING quoted_post_id
", post_id: post.id, post_number: post_number, topic_id: topic_id
results = results.to_a
if results.length > 0
ids << results[0]["quoted_post_id"].to_i
end
end
if ids.length > 0
exec_sql "DELETE FROM quoted_posts WHERE post_id = :post_id AND quoted_post_id NOT IN (:ids)",
post_id: post.id, ids: ids
end
end
end

View File

@ -487,6 +487,7 @@ class Topic < ActiveRecord::Base
# Grab any links that are present
TopicLink.extract_from(new_post)
QuotedPost.extract_from(new_post)
end
new_post

View File

@ -0,0 +1,54 @@
class AddQuotedPosts < ActiveRecord::Migration
def change
create_table :quoted_posts do |t|
t.integer :post_id, null: false
t.integer :quoted_post_id, null: false
t.timestamps
end
add_index :quoted_posts, [:post_id, :quoted_post_id], unique: true
add_index :quoted_posts, [:quoted_post_id, :post_id], unique: true
# NOTE this can be done in pg but too much of a headache
id = 0
while id = backfill_batch(id, 1000); end
end
def backfill_batch(start_id, batch_size)
results = execute <<SQL
SELECT id, cooked
FROM posts
WHERE raw like '%quote=%' AND id > #{start_id}
ORDER BY id
LIMIT #{batch_size}
SQL
max_id = nil
results.each do |row|
post_id, max_id = row["id"].to_i
doc = Nokogiri::HTML.fragment(row["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 uniq[[topic_id,post_number]]
uniq[[topic_id,post_number]] = true
execute "INSERT INTO quoted_posts(post_id, quoted_post_id, created_at, updated_at)
SELECT #{post_id}, id, created_at, updated_at
FROM posts
WHERE post_number = #{post_number} AND
topic_id = #{topic_id}"
end
end
max_id
end
end

View File

@ -266,6 +266,7 @@ class PostCreator
def extract_links
TopicLink.extract_from(@post)
QuotedPost.extract_from(@post)
end
def track_topic

View File

@ -0,0 +1,27 @@
require 'spec_helper'
describe QuotedPost do
it 'correctly extracts quotes in integration test' do
post1 = create_post
post2 = create_post(topic_id: post1.topic_id,
raw: "[quote=\"#{post1.user.username}, post: 1, topic:#{post1.topic_id}\"]\ntest\n[/quote]\nthis is a test post")
QuotedPost.find_by(post_id: post2.id, quoted_post_id: post1.id).should_not be_nil
end
it 'correctly handles deltas' do
post1 = Fabricate(:post)
post2 = Fabricate(:post)
post2.cooked = <<HTML
<aside class="quote" data-post="#{post1.post_number}" data-topic="#{post1.topic_id}"><div class="title"><div class="quote-controls"></div><img width="20" height="20" src="/user_avatar/meta.discourse.org/techapj/20/3281.png" class="avatar">techAPJ said:</div><blockquote><p>When the user will v</p></blockquote></aside>
HTML
QuotedPost.create!(post_id: post2.id, quoted_post_id: 999)
QuotedPost.extract_from(post2)
QuotedPost.where(post_id: post2.id).count.should == 1
QuotedPost.find_by(post_id: post2.id, quoted_post_id: post1.id).should_not be_nil
end
end