Fix #4178: add ability to mass undo tag edits.

Adds checkboxes to the /post_versions index allowing you to select and
undo multiple versions at once.
This commit is contained in:
evazion
2019-09-27 20:26:39 -05:00
parent 9000bc5cc6
commit d29bbbbd71
11 changed files with 150 additions and 34 deletions

View File

@@ -2,8 +2,10 @@ class PostVersionsController < ApplicationController
before_action :member_only, except: [:index, :search]
before_action :check_availabililty
respond_to :html, :xml, :json
respond_to :js, only: [:undo]
def index
# XXX statement timeouts
@post_versions = PostArchive.includes(:updater, post: [:versions]).search(search_params).paginate(params[:page], :limit => params[:limit], :search_count => params[:search])
respond_with(@post_versions)
end
@@ -13,14 +15,9 @@ class PostVersionsController < ApplicationController
def undo
@post_version = PostArchive.find(params[:id])
@post_version.undo!
if @post_version.post.visible?
@post_version.undo!
end
respond_with(@post_version) do |format|
format.js
end
respond_with(@post_version)
end
private

View File

@@ -36,6 +36,7 @@ export { default as Note } from '../src/javascripts/notes.js';
export { default as Post } from '../src/javascripts/posts.js.erb';
export { default as PostModeMenu } from '../src/javascripts/post_mode_menu.js';
export { default as PostTooltip } from '../src/javascripts/post_tooltips.js';
export { default as PostVersion } from '../src/javascripts/post_version.js';
export { default as RelatedTag } from '../src/javascripts/related_tag.js';
export { default as Shortcuts } from '../src/javascripts/shortcuts.js';
export { default as Upload } from '../src/javascripts/uploads.js.erb';

View File

@@ -0,0 +1,45 @@
import Utility from './utility';
let PostVersion = {};
PostVersion.initialize_all = function() {
if ($("#c-post-versions #a-index").length) {
PostVersion.initialize_undo();
}
};
PostVersion.initialize_undo = function() {
/* Expand the clickable area of the checkbox to the entire table cell. */
$(".post-version-select-column").on("click.danbooru", function(event) {
$(event.target).find(".post-version-select-checkbox:not(:disabled)").prop("checked", (_, checked) => !checked).change();
});
$("#post-version-select-all-checkbox").on("change.danbooru", function(event) {
$("td .post-version-select-checkbox:not(:disabled)").prop("checked", $("#post-version-select-all-checkbox").prop("checked")).change();
});
$(".post-version-select-checkbox").on("change.danbooru", function(event) {
let checked = $("td .post-version-select-checkbox:checked");
$("#subnav-undo-selected-link").text(`Undo selected (${checked.length})`).toggle(checked.length > 0);
});
$("#subnav-undo-selected-link").on("click.danbooru", PostVersion.undo_selected);
};
PostVersion.undo_selected = async function () {
event.preventDefault();
let updated = 0;
let selected_rows = $("td .post-version-select-checkbox:checked").parents("tr");
for (let row of selected_rows) {
let id = $(row).data("post-version-id");
await $.ajax(`/post_versions/${id}/undo.json`, { method: "PUT" });
updated++;
Utility.notice(`${updated}/${selected_rows.length} changes undone.`);
}
};
$(document).ready(PostVersion.initialize_all);
export default PostVersion;

View File

@@ -0,0 +1,9 @@
body.c-post-versions.a-index {
#subnav-undo-selected-link {
display: none;
}
.post-version-select-column {
min-width: 2em;
}
}

View File

@@ -1,4 +1,5 @@
class PostArchive < ApplicationRecord
class RevertError < Exception ; end
extend Memoist
belongs_to :post
@@ -218,7 +219,9 @@ class PostArchive < ApplicationRecord
source.gsub(/^http:\/\//, "").sub(/\/.+/, "")
end
def undo
def undo!
raise RevertError unless post.visible?
added = changes[:added_tags] - changes[:obsolete_added_tags]
removed = changes[:removed_tags] - changes[:obsolete_removed_tags]
@@ -239,11 +242,16 @@ class PostArchive < ApplicationRecord
post.tag_string = "#{post.tag_string} #{tag}".strip
end
end
post.save!
end
def undo!
undo
post.save!
def can_undo?(user)
version > 1 && post&.visible? && user.is_member?
end
def can_revert_to?(user)
post&.visible? && user.is_member?
end
def updater_name

View File

@@ -2,6 +2,11 @@
<table class="striped autofit">
<thead>
<tr>
<% if CurrentUser.user.is_builder? %>
<th class="post-version-select-column">
<label><input type="checkbox" id="post-version-select-all-checkbox" class="post-version-select-checkbox"></label>
</th>
<% end %>
<th width="5%">Post</th>
<th width="15%">Date</th>
<th width="10%">User</th>
@@ -18,7 +23,12 @@
</thead>
<tbody>
<% @post_versions.each do |post_version| %>
<tr id="post-version-<%= post_version.id %>">
<tr id="post-version-<%= post_version.id %>" data-post-version-id="<%= post_version.id %>">
<% if CurrentUser.user.is_builder? %>
<td class="post-version-select-column">
<input type="checkbox" class="post-version-select-checkbox" <%= "disabled" unless post_version.can_undo?(CurrentUser.user) %>>
</td>
<% end %>
<td><%= link_to("#{post_version.post_id}.#{post_version.id}", post_path(post_version.post_id)) %></td>
<td><%= compact_time(post_version.updated_at) %></td>
<td>
@@ -34,16 +44,14 @@
</td>
<% end %>
<td class="col-expand"><%= post_version_diff(post_version) %></td>
<% if CurrentUser.is_member? %>
<td>
<% if post_version.visible? %>
<% if post_version.version != 1 %>
<%= link_to "Undo", undo_post_version_path(post_version), :method => :put, :remote => true %> |
<% end %>
<%= link_to "Revert to", revert_post_path(post_version.post_id, :version_id => post_version.id), :method => :put, :remote => true %>
<% end %>
</td>
<% end %>
<td>
<% if post_version.can_undo?(CurrentUser.user) %>
<%= link_to "Undo", undo_post_version_path(post_version), method: :put, remote: true, class: "post-version-undo-link" %> |
<% end %>
<% if post_version.can_revert_to?(CurrentUser.user) %>
<%= link_to "Revert to", revert_post_path(post_version.post_id, version_id: post_version.id), method: :put, remote: true %>
<% end %>
</td>
</tr>
<% end %>
</tbody>

View File

@@ -4,4 +4,7 @@
<%= subnav_link_to "Search", search_post_versions_path %>
<%= subnav_link_to "Changes", post_versions_path %>
<%= subnav_link_to "Help", wiki_pages_path(:title => "help:posts") %>
<% if params[:action] == "index" %>
| <%= subnav_link_to "Undo selected", "" %>
<% end %>
<% end %>

View File

@@ -2,6 +2,11 @@
<table class="striped autofit">
<thead>
<tr>
<% if CurrentUser.user.is_builder? %>
<th class="post-version-select-column">
<label><input type="checkbox" id="post-version-select-all-checkbox" class="post-version-select-checkbox"></label>
</th>
<% end %>
<th width="5%">Post</th>
<th width="15%">Date</th>
<th width="10%">User</th>
@@ -18,7 +23,12 @@
</thead>
<tbody>
<% @post_versions.each do |post_version| %>
<tr id="post-version-<%= post_version.id %>">
<tr id="post-version-<%= post_version.id %>" data-post-version-id="<%= post_version.id %>">
<% if CurrentUser.user.is_builder? %>
<td class="post-version-select-column">
<input type="checkbox" class="post-version-select-checkbox" <%= "disabled" unless post_version.can_undo?(CurrentUser.user) %>>
</td>
<% end %>
<td>
<%= link_to("#{post_version.post_id}.#{post_version.id}", post_path(post_version.post_id)) %>
<%= link_to "»", post_versions_path(search: {post_id: post_version.post_id}) %>
@@ -37,18 +47,13 @@
</td>
<% end %>
<td class="col-expand"><%= post_version_diff(post_version) %></td>
<% if CurrentUser.is_member? %>
<td>
<% if post_version.visible? %>
<% if post_version.version != 1 %>
<%= link_to "Undo", undo_post_version_path(post_version), :method => :put, :remote => true %>
<% end %>
<% end %>
</td>
<% end %>
<td>
<% if post_version.can_undo?(CurrentUser.user) %>
<%= link_to "Undo", undo_post_version_path(post_version), method: :put, remote: true, class: "post-version-undo-link" %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>

View File

@@ -1 +1 @@
location.reload();
Danbooru.Utility.notice("1 change undone.");

View File

@@ -0,0 +1,33 @@
require "application_system_test_case"
class PostVersionTest < ApplicationSystemTestCase
context "Post versions" do
setup do
@user = create(:builder_user)
as @user do
@post = create(:post, tag_string: "tagme")
travel 2.hours
@post.update!(tag_string: "touhou")
travel 2.hours
@post.update!(tag_string: "touhou bkub")
travel 2.hours
end
signin @user
visit post_versions_path
end
context "clicking the undo selected button" do
should "undo all selected post versions" do
check id: "post-version-select-all-checkbox"
assert all("td .post-version-select-checkbox:not(:disabled)").all?(&:checked?)
click_link "subnav-undo-selected-link"
assert_selector "#notice span.prose", text: "2/2 changes undone."
assert_equal("tagme", @post.reload.tag_string)
end
end
end
end

View File

@@ -6,4 +6,11 @@ module SystemTestHelper
fill_in "Password confirmation", with: password
click_button "Sign up"
end
def signin(user)
visit new_session_path
fill_in "Name", with: user.name
fill_in "Password", with: user.password
click_button "Submit"
end
end