Merge pull request #4247 from BrokenEagle/pool-version-enhancements

Add pool version enhancements
This commit is contained in:
evazion
2020-01-08 19:34:25 -06:00
committed by GitHub
14 changed files with 204 additions and 71 deletions

View File

@@ -12,6 +12,9 @@ class PoolVersionsController < ApplicationController
respond_with(@pool_versions)
end
def search
end
def diff
@pool_version = PoolArchive.find(params[:id])

View File

@@ -3,4 +3,24 @@ module PoolVersionsHelper
params.dig(:search, :pool_id).present? ? :revert : :standard
end
end
def pool_version_status_diff(pool_version)
cur = pool_version
prev = pool_version.previous
return "New" if prev.blank?
status = []
status += ["Renamed"] if cur.name != prev.name
status += ["DescChanged"] if cur.description != prev.description
status += ["Deleted"] if cur.is_deleted? && !prev.is_deleted?
status += ["Undeleted"] if !cur.is_deleted? && prev.is_deleted?
status += ["Activated"] if cur.is_active? && !prev.is_active?
status += ["Deactivated"] if !cur.is_active? && prev.is_active?
status.join(" ")
end
def pool_page_diff(pool_version, other_version)
pattern = Regexp.new('(?:<.+?>)|(?:\w+)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)')
DiffBuilder.new(other_version.description, pool_version.description, pattern).build
end
end

View File

@@ -12,59 +12,13 @@ module WikiPageVersionsHelper
status.join(" ")
end
def wiki_page_diff(thispage, otherpage)
def wiki_other_names_diff(thispage, otherpage)
pattern = Regexp.new('\S+|\s+')
DiffBuilder.new("#{thispage.other_names}\n\n", "#{otherpage.other_names}\n\n", pattern).build
end
def wiki_body_diff(thispage, otherpage)
pattern = Regexp.new('(?:<.+?>)|(?:\w+)|(?:[ \t]+)|(?:\r?\n)|(?:.+?)')
other_names_pattern = Regexp.new('\S+|\s+')
thisarr = thispage.body.scan(pattern)
otharr = otherpage.body.scan(pattern)
if thispage.other_names.present? || otherpage.other_names.present?
thisarr = "#{thispage.other_names}\n\n".scan(other_names_pattern) + thisarr
otharr = "#{otherpage.other_names}\n\n".scan(other_names_pattern) + otharr
end
cbo = Diff::LCS::ContextDiffCallbacks.new
diffs = thisarr.diff(otharr, cbo)
escape_html = ->(str) {str.gsub(/&/, '&amp;').gsub(/</, '&lt;').gsub(/>/, '&gt;')}
output = thisarr
output.each { |q| q.replace(escape_html[q]) }
diffs.reverse_each do |hunk|
newchange = hunk.max {|a, b| a.old_position <=> b.old_position}
newstart = newchange.old_position
oldstart = hunk.min {|a, b| a.old_position <=> b.old_position}.old_position
if newchange.action == '+'
output.insert(newstart, '</ins>')
end
hunk.reverse_each do |chg|
case chg.action
when '-'
oldstart = chg.old_position
output[chg.old_position] = '<br>' if chg.old_element.match(/^\r?\n$/)
when '+'
if chg.new_element.match(/^\r?\n$/)
output.insert(chg.old_position, '<br>')
else
output.insert(chg.old_position, (escape_html[chg.new_element]).to_s)
end
end
end
if newchange.action == '+'
output.insert(newstart, '<ins>')
end
if hunk[0].action == '-'
output.insert((newstart == oldstart || newchange.action != '+') ? newstart + 1 : newstart, '</del>')
output.insert(oldstart, '<del>')
end
end
output.join.gsub(/\r?\n/, '<br>').html_safe
DiffBuilder.new(thispage.body, otherpage.body, pattern).build
end
end

View File

@@ -0,0 +1,17 @@
div#c-pool-versions {
#a-diff {
del {
background: var(--wiki-page-versions-diff-del-background);
text-decoration: none;
}
ins {
background: var(--wiki-page-versions-diff-ins-background);
text-decoration: none;
}
span.paragraph-mark {
opacity: 0.25;
}
}
}

View File

@@ -9,6 +9,10 @@ div#c-wiki-page-versions {
background: var(--wiki-page-versions-diff-ins-background);
text-decoration: none;
}
span.paragraph-mark {
opacity: 0.25;
}
}
#a-index {

View File

@@ -0,0 +1,57 @@
class DiffBuilder
attr_reader :this_text, :that_text, :pattern
def initialize(this_text, that_text, pattern)
@this_text = this_text
@that_text = that_text
@pattern = pattern
end
def build
thisarr = this_text.scan(pattern)
otharr = that_text.scan(pattern)
cbo = Diff::LCS::ContextDiffCallbacks.new
diffs = thisarr.diff(otharr, cbo)
escape_html = ->(str) {str.gsub(/&/, '&amp;').gsub(/</, '&lt;').gsub(/>/, '&gt;')}
output = thisarr
output.each { |q| q.replace(escape_html[q]) }
diffs.reverse_each do |hunk|
newchange = hunk.max {|a, b| a.old_position <=> b.old_position}
newstart = newchange.old_position
oldstart = hunk.min {|a, b| a.old_position <=> b.old_position}.old_position
if newchange.action == '+'
output.insert(newstart, '</ins>')
end
hunk.reverse_each do |chg|
case chg.action
when '-'
oldstart = chg.old_position
output[chg.old_position] = '<span class="paragraph-mark">¶</span><br>' if chg.old_element.match(/^\r?\n$/)
when '+'
if chg.new_element.match(/^\r?\n$/)
output.insert(chg.old_position, '<span class="paragraph-mark">¶</span><br>')
else
output.insert(chg.old_position, (escape_html[chg.new_element]).to_s)
end
end
end
if newchange.action == '+'
output.insert(newstart, '<ins>')
end
if hunk[0].action == '-'
output.insert((newstart == oldstart || newchange.action != '+') ? newstart + 1 : newstart, '</del>')
output.insert(oldstart, '<del>')
end
end
output.join.gsub(/\r?\n/, '<span class="paragraph-mark">¶</span><br>').html_safe
end
end

View File

@@ -21,14 +21,34 @@ class PoolArchive < ApplicationRecord
where_array_includes_any(:added_post_ids, [post_id]).or(where_array_includes_any(:removed_post_ids, [post_id]))
end
def name_matches(name)
name = normalize_name_for_search(name)
name = "*#{name}*" unless name =~ /\*/
where_ilike(:name, name)
end
def search(params)
q = super
q = q.search_attributes(params, :pool_id, :post_ids, :added_post_ids, :removed_post_ids, :updater, :description, :description_changed, :name, :name_changed, :version, :is_active, :is_deleted, :category)
q = q.search_attributes(params, :pool_id, :post_ids, :added_post_ids, :removed_post_ids, :updater_id, :description, :description_changed, :name, :name_changed, :version, :is_active, :is_deleted, :category)
if params[:post_id]
q = q.for_post_id(params[:post_id].to_i)
end
if params[:name_matches].present?
q = q.name_matches(params[:name_matches])
end
if params[:updater_name].present?
q = q.where(updater_id: User.name_to_id(params[:updater_name]))
end
if params[:is_new].to_s.truthy?
q = q.where(version: 1)
elsif params[:is_new].to_s.falsy?
q = q.where("version != 1")
end
q.apply_default_order(params)
end
end
@@ -61,6 +81,14 @@ class PoolArchive < ApplicationRecord
sqs_service.send_message(msg, message_group_id: "pool:#{pool.id}")
end
def self.normalize_name(name)
name.gsub(/[_[:space:]]+/, "_").gsub(/\A_|_\z/, "")
end
def self.normalize_name_for_search(name)
normalize_name(name).mb_chars.downcase
end
def build_diff(other = previous)
diff = {}

View File

@@ -1,18 +1,21 @@
<div id="p-<%= pool_versions_listing_type %>-listing">
<%= table_for @pool_versions, {class: "striped autofit", width: "100%"} do |t| %>
<% t.column th: {width: "3%"} do |pool_version| %>
<%= link_to_if pool_version.previous.present?, "diff", diff_pool_version_path(pool_version.id) %>
<% end %>
<% t.column "Pool" do |pool_version| %>
<%= link_to pool_version.pretty_name, pool_path(pool_version.pool_id), class: "pool-category-#{pool_version.pool.category}" %>
<%= link_to "»", pool_versions_path(search: { pool_id: pool_version.pool_id }), class: "pool-category-#{pool_version.pool.category}" %>
<% end %>
<% t.column "Changes", td: { class: "col-expand" } do |pool_version| %>
<% t.column "Post Changes", td: { class: "col-expand" } do |pool_version| %>
<%= render "pool_versions/diff", diff: pool_version.build_diff %>
<% end %>
<% t.column "Post Count" do |pool_version| %>
<%= link_to pool_version.post_ids.size, pool_versions_path(search: { pool_id: pool_version.pool_id }) %>
<% end %>
<% t.column "Desc Chg" do |pool_version| %>
<%= link_to_if pool_version.description_changed, pool_version.description_changed, diff_pool_version_path(pool_version.id) %>
<% t.column "Status", td: {class: "col-expand"} do |pool_version| %>
<%= pool_version_status_diff(pool_version) %>
<% end %>
<% t.column "Updater" do |pool_version| %>
<% if pool_version.updater %>

View File

@@ -0,0 +1,5 @@
<% content_for(:secondary_links) do %>
<%= quick_search_form_for(:name_matches, pool_versions_path, "pools", autocomplete: "pool") %>
<%= subnav_link_to "Listing", pool_versions_path %>
<%= subnav_link_to "Search", search_pool_versions_path %>
<% end %>

View File

@@ -2,20 +2,37 @@
<div id="a-diff">
<h1>Pool Version Comparison: <%= @pool_version.name %></h1>
<ul>
<li>
<strong>Posts</strong>:
<%= render "pool_versions/diff", diff: @pool_version.build_diff(@other_version) %>
</li>
<% if @other_version %>
<li><strong>Old Desc</strong>: <%= @other_version.description %></li>
<% end %>
<li><strong>New Desc</strong>: <%= @pool_version.description %></li>
</ul>
<% if @other_version.present? %>
<p>Showing differences between <%= compact_time @pool_version.updated_at %> (<%= link_to_user @pool_version.updater %>) and <%= compact_time @other_version.updated_at %> (<%= link_to_user @other_version.updater %>)</p>
<div>
<h2>Name:</h2>
<p>
<% if @pool_version.name != @other_version.name %>
<del><%= @other_version.name %></del> -> <ins><%= @pool_version.name %></ins>
<% else %>
<%= @pool_version.name %>
<% end %>
</p>
</div>
<div>
<h2>Posts:</h2>
<p><%= render "pool_versions/diff", diff: @pool_version.build_diff(@other_version) %></p>
</div>
<div>
<h2>Description:</h2>
<p>
<% if @pool_version.description != @other_version.description %>
<%= pool_page_diff(@pool_version, @other_version) %>
<% else %>
<i>Unchanged.</i>
<% end %>
</p>
</div>
<% end %>
</div>
</div>
<%= render "pools/secondary_links" %>
<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Pool Version Comparison - <%= @pool_version.name %> - <%= Danbooru.config.app_name %>

View File

@@ -8,4 +8,4 @@
</div>
</div>
<%= render "pools/secondary_links" %>
<%= render "secondary_links" %>

View File

@@ -0,0 +1,19 @@
<div id="c-pool-versions">
<div id="a-search">
<h1>Search Changes</h1>
<%= search_form_for(pool_versions_path) do |f| %>
<%= f.input :updater_name, label: "Updater", input_html: { value: params.dig(:search, :updater_name), "data-autocomplete": "user" } %>
<%= f.input :name_matches, label: "Pool", input_html: { value: params.dig(:search, :name_matches), "data-autocomplete": "pool" } %>
<%= f.input :category, label: "Category", collection: [["Series", "series"], ["Collection", "collection"]], include_blank: true %>
<%= f.input :is_new, label: "New?", collection: [["Yes", true], ["No", false]], include_blank: true %>
<%= f.input :name_changed, label: "Name changed?", collection: [["Yes", true], ["No", false]], include_blank: true %>
<%= f.input :description_changed, label: "Description changed?", collection: [["Yes", true], ["No", false]], include_blank: true %>
<%= f.input :is_active, label: "Active?", collection: [["Yes", true], ["No", false]], include_blank: true %>
<%= f.input :is_banned, label: "Deleted?", collection: [["Yes", true], ["No", false]], include_blank: true %>
<%= f.submit "Search" %>
<% end %>
</div>
</div>
<%= render "secondary_links" %>

View File

@@ -7,7 +7,10 @@
<p>Showing differences between <%= compact_time @thispage.updated_at %> (<%= link_to_user @thispage.updater %>) and <%= compact_time @otherpage.updated_at %> (<%= link_to_user @otherpage.updater %>)</p>
<div>
<%= wiki_page_diff(@thispage, @otherpage) %>
<%= wiki_other_names_diff(@thispage, @otherpage) %>
</div>
<div>
<%= wiki_body_diff(@thispage, @otherpage) %>
</div>
<% else %>
<p>The artist requested removal of this page.</p>

View File

@@ -191,6 +191,9 @@ Rails.application.routes.draw do
member do
get :diff
end
collection do
get :search
end
end
resources :post_replacements, :only => [:index, :new, :create, :update]
resources :post_votes, only: [:index]