forked from e621ng/e621ng
* Refactored post history. Each post now has a single history record. This history record has multiple revisions, serialized as JSON in a text field.
This commit is contained in:
parent
6076788d60
commit
f3b4312ef3
1
Gemfile
1
Gemfile
@ -17,5 +17,6 @@ gem "haml"
|
||||
gem "simple_form"
|
||||
gem "mechanize"
|
||||
gem "nokogiri"
|
||||
gem "meta_search"
|
||||
|
||||
gem "will_paginate", :git => "http://github.com/mislav/will_paginate.git", :branch => "rails3"
|
||||
|
@ -61,6 +61,11 @@ GEM
|
||||
mechanize (1.0.0)
|
||||
nokogiri (>= 1.2.1)
|
||||
memcache-client (1.8.5)
|
||||
meta_search (0.9.7.2)
|
||||
actionpack (~> 3.0.0)
|
||||
activerecord (~> 3.0.0)
|
||||
activesupport (~> 3.0.0)
|
||||
arel (~> 1.0.1)
|
||||
mime-types (1.16)
|
||||
mocha (0.9.9)
|
||||
rake
|
||||
@ -107,6 +112,7 @@ DEPENDENCIES
|
||||
imagesize
|
||||
mechanize
|
||||
memcache-client
|
||||
meta_search
|
||||
mocha
|
||||
nokogiri
|
||||
pg
|
||||
|
6
app/controllers/post_histories_controller.rb
Normal file
6
app/controllers/post_histories_controller.rb
Normal file
@ -0,0 +1,6 @@
|
||||
class PostHistoriesController < ApplicationController
|
||||
def index
|
||||
@search = PostHistory.search(params[:search])
|
||||
@histories = @search.paginate(:page => params[:page], :per_page => 20)
|
||||
end
|
||||
end
|
@ -1,4 +0,0 @@
|
||||
class PostVersionsController < ApplicationController
|
||||
def index
|
||||
end
|
||||
end
|
@ -1,5 +1,60 @@
|
||||
class PostHistory < ActiveRecord::Base
|
||||
class Error < Exception ; end
|
||||
|
||||
class Revision
|
||||
attr_accessor :prev, :hash, :diff, :tag_array
|
||||
|
||||
def initialize(hash)
|
||||
@hash = hash
|
||||
@diff = {}
|
||||
@tag_array = Tag.scan_tags(@hash["tag_string"])
|
||||
end
|
||||
|
||||
def calculate_diff
|
||||
if prev.nil?
|
||||
diff[:add] = tag_array
|
||||
diff[:del] = []
|
||||
diff[:rating] = rating
|
||||
diff[:source] = source
|
||||
diff[:parent_id] = parent_id
|
||||
else
|
||||
diff[:del] = prev.tag_array - tag_array
|
||||
diff[:add] = tag_array - prev.tag_array
|
||||
|
||||
if prev.rating != rating
|
||||
diff[:rating] = rating
|
||||
end
|
||||
|
||||
if prev.source != source
|
||||
diff[:source] = source
|
||||
end
|
||||
|
||||
if prev.parent_id != parent_id
|
||||
diff[:parent_id]= parent_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def rating
|
||||
hash["rating"]
|
||||
end
|
||||
|
||||
def source
|
||||
hash["source"]
|
||||
end
|
||||
|
||||
def parent_id
|
||||
hash["parent_id"]
|
||||
end
|
||||
|
||||
def updated_at
|
||||
hash["updated_at"]
|
||||
end
|
||||
|
||||
def updater_id
|
||||
hash["user_id"]
|
||||
end
|
||||
end
|
||||
|
||||
before_validation :initialize_revisions, :on => :create
|
||||
belongs_to :post
|
||||
@ -37,4 +92,19 @@ class PostHistory < ActiveRecord::Base
|
||||
write_attribute(:revisions, (revisions << revision).to_json)
|
||||
save
|
||||
end
|
||||
|
||||
def each_revision(&block)
|
||||
array = revisions.map {|x| Revision.new(x)}
|
||||
link_revisions(array)
|
||||
array.each {|x| x.calculate_diff}
|
||||
array.each(&block)
|
||||
end
|
||||
|
||||
private
|
||||
def link_revisions(array)
|
||||
1.upto(array.size - 1) do |i|
|
||||
array[i].prev = array[i - 1]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
19
app/presenters/post_history_presenter.rb
Normal file
19
app/presenters/post_history_presenter.rb
Normal file
@ -0,0 +1,19 @@
|
||||
class PostHistoryPresenter < Presenter
|
||||
attr_reader :revision
|
||||
|
||||
def initialize(revision)
|
||||
@revision = revision
|
||||
end
|
||||
|
||||
def changes
|
||||
|
||||
end
|
||||
|
||||
def updated_at
|
||||
revision["updated_at"]
|
||||
end
|
||||
|
||||
def updater_name
|
||||
User.id_to_name(revision["user_id"].to_i)
|
||||
end
|
||||
end
|
@ -1,7 +1,24 @@
|
||||
class PostPresenter < Presenter
|
||||
def self.preview(post)
|
||||
flags = []
|
||||
flags << "pending" if post.is_pending?
|
||||
flags << "flagged" if post.is_flagged?
|
||||
flags << "removed" if post.is_removed?
|
||||
|
||||
html = %{<article id="post_#{post.id}" data-id="#{post.id}" data-tags="#{h(post.tag_string)}" data-uploader="#{h(post.uploader_name)}" data-rating="#{post.rating}" data-width="#{post.image_width}" data-height="#{post.image_height}" data-flags="#{flags.join(' ')}">}
|
||||
html << %{<a href="/posts/#{post.id}">}
|
||||
html << %{<img src="#{post.preview_file_url}">}
|
||||
html << %{</a>}
|
||||
html << %{</article>}
|
||||
end
|
||||
|
||||
def initialize(post)
|
||||
@post = post
|
||||
end
|
||||
|
||||
def preview_html
|
||||
PostPresenter.preview(@post)
|
||||
end
|
||||
|
||||
def image_html(template)
|
||||
return template.content_tag("p", "This image was deleted.") if @post.is_removed? && !CurrentUser.user.is_janitor?
|
||||
|
@ -50,16 +50,7 @@ class PostSetPresenter < Presenter
|
||||
html = ""
|
||||
|
||||
posts.each do |post|
|
||||
flags = []
|
||||
flags << "pending" if post.is_pending?
|
||||
flags << "flagged" if post.is_flagged?
|
||||
flags << "removed" if post.is_removed?
|
||||
|
||||
html << %{<article id="post_#{post.id}" data-id="#{post.id}" data-tags="#{h(post.tag_string)}" data-uploader="#{h(post.uploader_name)}" data-rating="#{post.rating}" data-width="#{post.image_width}" data-height="#{post.image_height}" data-flags="#{flags.join(' ')}">}
|
||||
html << %{<a href="/posts/#{post.id}">}
|
||||
html << %{<img src="#{post.preview_file_url}">}
|
||||
html << %{</a>}
|
||||
html << %{</article>}
|
||||
html << PostPresenter.preview(post)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
|
35
app/views/post_histories/index.html.erb
Normal file
35
app/views/post_histories/index.html.erb
Normal file
@ -0,0 +1,35 @@
|
||||
<div class="post_histories">
|
||||
<div class="index">
|
||||
<h1>Post History</h1>
|
||||
|
||||
<% @histories.each do |history| %>
|
||||
<div class="post">
|
||||
<div class="preview">
|
||||
<%= history.post.presenter.preview_html %>
|
||||
</div>
|
||||
|
||||
<div class="history">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Changes</th>
|
||||
<th>Date</th>
|
||||
<th>Updater</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% history.each_revision do |revision| %>
|
||||
<tr>
|
||||
<td><%= revision.presenter.changes %></td>
|
||||
<td><%= revision.presenter.updated_at %></td>
|
||||
<td><%= revision.presenter.updater_name %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -39,7 +39,7 @@ Danbooru::Application.routes.draw do
|
||||
end
|
||||
end
|
||||
resources :post_moderation_details
|
||||
resources :post_versions
|
||||
resources :post_histories
|
||||
resources :post_votes
|
||||
resources :reports
|
||||
resources :sessions
|
||||
|
@ -7,6 +7,7 @@ class PostHistoryTest < ActiveSupport::TestCase
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
MEMCACHE.flush_all
|
||||
PostHistory.stubs(:revision_time).returns("TIME")
|
||||
end
|
||||
|
||||
teardown do
|
||||
@ -15,19 +16,48 @@ class PostHistoryTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "create a revision after creation" do
|
||||
PostHistory.stubs(:revision_time).returns("TIME")
|
||||
post = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
assert_equal(1, post.revisions.size)
|
||||
assert_equal({"source"=>nil, "rating"=>"q", "tag_string"=>"aaa bbb ccc", "parent_id"=>nil, "user_id"=>1, "ip_addr"=>"127.0.0.1", "updated_at"=>"TIME"}, post.revisions.last)
|
||||
assert_equal({"source"=>nil, "rating"=>"q", "tag_string"=>"aaa bbb ccc", "parent_id"=>nil, "user_id"=>@user.id, "ip_addr"=>"127.0.0.1", "updated_at"=>"TIME"}, post.revisions.last)
|
||||
end
|
||||
|
||||
should "create additional revisions after updating" do
|
||||
PostHistory.stubs(:revision_time).returns("TIME")
|
||||
post = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
post.update_attributes(:tag_string => "bbb ccc ddd")
|
||||
post.reload
|
||||
assert_equal(2, post.revisions.size)
|
||||
assert_equal({"source"=>nil, "rating"=>"q", "tag_string"=>"bbb ccc ddd", "parent_id"=>nil, "user_id"=>3, "ip_addr"=>"127.0.0.1", "updated_at"=>"TIME"}, post.revisions.last)
|
||||
assert_equal({"source"=>nil, "rating"=>"q", "tag_string"=>"bbb ccc ddd", "parent_id"=>nil, "user_id"=>@user.id, "ip_addr"=>"127.0.0.1", "updated_at"=>"TIME"}, post.revisions.last)
|
||||
end
|
||||
|
||||
context "history" do
|
||||
setup do
|
||||
@post = Factory.create(:post, :tag_string => "aaa bbb ccc", :source => "xyz", :rating => "q")
|
||||
@post.update_attributes(:tag_string => "bbb ccc ddd", :source => "abc", :rating => "s")
|
||||
@post.update_attributes(:tag_string => "ccc ddd eee")
|
||||
@revisions = []
|
||||
@post.history.each_revision do |revision|
|
||||
@revisions << revision
|
||||
end
|
||||
end
|
||||
|
||||
should "link revisions together" do
|
||||
assert_nil(@revisions[0].prev)
|
||||
assert_equal(@revisions[0], @revisions[1].prev)
|
||||
assert_equal(@revisions[1], @revisions[2].prev)
|
||||
end
|
||||
|
||||
should "iterate over its revisions" do
|
||||
assert_equal(3, @revisions.size)
|
||||
assert_equal(%w(aaa bbb ccc), @revisions[0].tag_array)
|
||||
assert_equal(%w(bbb ccc ddd), @revisions[1].tag_array)
|
||||
assert_equal(%w(ccc ddd eee), @revisions[2].tag_array)
|
||||
end
|
||||
|
||||
should "create a diff for each revision detailing what changed" do
|
||||
assert_equal({:add=>["aaa", "bbb", "ccc"], :del=>[], :rating=>"q", :source=>"xyz", :parent_id=>nil}, @revisions[0].diff)
|
||||
assert_equal({:del=>["aaa"], :add=>["ddd"], :rating=>"s", :source=>"abc"}, @revisions[1].diff)
|
||||
assert_equal({:del=>["bbb"], :add=>["eee"]}, @revisions[2].diff)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user