From f6753d3d4642da5166d7466d53d707b89b6ed90b Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 28 May 2014 12:30:43 +1000 Subject: [PATCH] FEATURE: automatically rebake out-of-date posts --- app/jobs/scheduled/periodical_updates.rb | 3 ++ app/models/post.rb | 34 ++++++++++++++ .../20140528015354_add_baked_at_to_posts.rb | 5 ++ lib/tasks/posts.rake | 17 +------ spec/models/post_spec.rb | 46 +++++++++++++------ 5 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 db/migrate/20140528015354_add_baked_at_to_posts.rb diff --git a/app/jobs/scheduled/periodical_updates.rb b/app/jobs/scheduled/periodical_updates.rb index 6ac90042c7e..88de72d79ca 100644 --- a/app/jobs/scheduled/periodical_updates.rb +++ b/app/jobs/scheduled/periodical_updates.rb @@ -26,6 +26,9 @@ module Jobs # Automatically close stuff that we missed Topic.auto_close + + # Forces rebake of old posts where needed + Post.rebake_old(250) end end diff --git a/app/models/post.rb b/app/models/post.rb index 629fc48b1be..1ba2829d5ef 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -15,6 +15,10 @@ class Post < ActiveRecord::Base include Trashable include HasCustomFields + # rebake all posts baked before this date + # in our periodical job + REBAKE_BEFORE = Time.new(2014,5,27) + rate_limit rate_limit :limit_posts_per_day @@ -310,6 +314,35 @@ class Post < ActiveRecord::Base PostRevisor.new(self).revise!(updated_by, new_raw, opts) end + def self.rebake_old(limit) + Post.where('baked_at IS NULL OR baked_at < ?', REBAKE_BEFORE) + .limit(limit).each do |p| + begin + p.rebake! + rescue => e + Discourse.handle_exception(e) + end + end + end + + def rebake!(opts={}) + new_cooked = cook( + raw, + topic_id: topic_id, + invalidate_oneboxes: opts.fetch(:invalidate_oneboxes, false) + ) + old_cooked = cooked + + update_columns(cooked: new_cooked, baked_at: Time.new) + + # Extracts urls from the body + TopicLink.extract_from self + # make sure we trigger the post process + trigger_post_process(true) + + new_cooked != old_cooked + end + def set_owner(new_user, actor) revise(actor, self.raw, { new_user: new_user, @@ -357,6 +390,7 @@ class Post < ActiveRecord::Base before_save do self.last_editor_id ||= user_id self.cooked = cook(raw, topic_id: topic_id) unless new_record? + self.baked_at = Time.new end after_save do diff --git a/db/migrate/20140528015354_add_baked_at_to_posts.rb b/db/migrate/20140528015354_add_baked_at_to_posts.rb new file mode 100644 index 00000000000..bd97a56f104 --- /dev/null +++ b/db/migrate/20140528015354_add_baked_at_to_posts.rb @@ -0,0 +1,5 @@ +class AddBakedAtToPosts < ActiveRecord::Migration + def change + add_column :posts, :baked_at, :datetime + end +end diff --git a/lib/tasks/posts.rake b/lib/tasks/posts.rake index ddc716bbe97..5b448e3c196 100644 --- a/lib/tasks/posts.rake +++ b/lib/tasks/posts.rake @@ -9,25 +9,12 @@ task 'posts:refresh_oneboxes' => :environment do end def rebake_post(post,opts) - cooked = post.cook( - post.raw, - topic_id: post.topic_id, - invalidate_oneboxes: opts.fetch(:invalidate_oneboxes, false) - ) - - if cooked != post.cooked - Post.exec_sql('update posts set cooked = ? where id = ?', cooked, post.id) - post.cooked = cooked + changed = post.rebake!(opts) + if changed putc "#" else putc "." end - - # Extracts urls from the body - TopicLink.extract_from post - # make sure we trigger the post process - post.trigger_post_process(true) - rescue => e puts "\n\nFailed to bake topic_id #{post.topic_id} post_id #{post.id} #{e}\n#{e.backtrace.join("\n")} \n\n" end diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index fda07e82329..1ef88e0e352 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -11,8 +11,6 @@ describe Post do Fabricate.build(:post, args) end - it { should belong_to :user } - it { should belong_to :topic } it { should validate_presence_of :raw } # Min/max body lengths, respecting padding @@ -20,17 +18,6 @@ describe Post do it { should_not allow_value("x" * (SiteSetting.max_post_length + 1)).for(:raw) } it { should_not allow_value((" " * SiteSetting.min_post_length) + "x").for(:raw) } - it { should have_many :post_replies } - it { should have_many :replies } - - it { should have_many :post_uploads } - it { should have_many :uploads } - - it { should have_many :post_details } - - it { should have_many :post_revisions } - it { should have_many :revisions} - it { should rate_limit } let(:topic) { Fabricate(:topic) } @@ -805,11 +792,11 @@ describe Post do post.has_host_spam?.should == false - SiteSetting.stubs(:newuser_spam_host_threshold).returns(1) + SiteSetting.newuser_spam_host_threshold = 1 post.has_host_spam?.should == true - SiteSetting.stubs(:white_listed_spam_host_domains).returns("bla.com|boo.com | somesite.com ") + SiteSetting.white_listed_spam_host_domains = "bla.com|boo.com | somesite.com " post.has_host_spam?.should == false end end @@ -826,4 +813,33 @@ describe Post do post.custom_fields.should == {"Tommy" => "Hanks", "Vincent" => "Vega"} end + describe "#rebake!" do + it "will rebake a post correctly" do + post = create_post + post.baked_at.should_not == nil + first_baked = post.baked_at + first_cooked = post.cooked + + Post.exec_sql("UPDATE posts SET cooked = 'frogs' WHERE id = ?", post.id) + post.reload + + result = post.rebake! + + post.baked_at.should_not == first_baked + post.cooked.should == first_cooked + result.should == true + end + end + + describe ".rebake_old" do + it "will catch posts it needs to rebake" do + post = create_post + post.update_column(:baked_at, Time.new(2000,1,1)) + Post.rebake_old(100) + + post.reload + post.baked_at.should > 1.day.ago + end + end + end