From b6f9c9a866a5cced78288d9251708ff87557da51 Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 4 Jan 2021 18:16:43 -0600 Subject: [PATCH] post regenerations: regenerate posts asynchronously. Regenerate posts asynchronously using a delayed job. Regenerating a post can be slow because it involves downloading the original file, regenerating the thumbnails, and redistributing the new thumbnails back to the image servers. It's better to run this in the background, especially if a user is trying to regenerate posts in bulk. The downside is there's no notification to the user when the regeneration is complete. You have to check the modactions log to see when it's finished. --- .../post_regenerations_controller.rb | 5 +- app/jobs/regenerate_post_job.rb | 8 +++ app/models/post.rb | 4 ++ app/views/post_regenerations/create.js.erb | 1 - .../posts/partials/show/_options.html.erb | 2 +- .../post_regenerations_controller_test.rb | 50 +++++++++++++++++-- 6 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 app/jobs/regenerate_post_job.rb delete mode 100644 app/views/post_regenerations/create.js.erb diff --git a/app/controllers/post_regenerations_controller.rb b/app/controllers/post_regenerations_controller.rb index 1d5b60244..d465ac3f8 100644 --- a/app/controllers/post_regenerations_controller.rb +++ b/app/controllers/post_regenerations_controller.rb @@ -1,9 +1,10 @@ class PostRegenerationsController < ApplicationController - respond_to :xml, :json, :js + respond_to :xml, :json, :html def create @post = authorize Post.find(params[:post_id]), :regenerate? - @post.regenerate!(params[:category], CurrentUser.user) + @post.regenerate_later!(params[:category], CurrentUser.user) + flash[:notice] = "Post regeneration scheduled, press Ctrl+F5 in a few seconds to refresh the image" respond_with(@post) end diff --git a/app/jobs/regenerate_post_job.rb b/app/jobs/regenerate_post_job.rb new file mode 100644 index 000000000..f9905d935 --- /dev/null +++ b/app/jobs/regenerate_post_job.rb @@ -0,0 +1,8 @@ +class RegeneratePostJob < ApplicationJob + queue_as :default + queue_with_priority 20 + + def perform(post:, category:, user:) + post.regenerate!(category, user) + end +end diff --git a/app/models/post.rb b/app/models/post.rb index 1a67e0a64..d3a3df27e 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1326,6 +1326,10 @@ class Post < ApplicationRecord end concerning :RegenerationMethods do + def regenerate_later!(category, user) + RegeneratePostJob.perform_later(post: self, category: category, user: user) + end + def regenerate!(category, user) if category == "iqdb" update_iqdb_async diff --git a/app/views/post_regenerations/create.js.erb b/app/views/post_regenerations/create.js.erb deleted file mode 100644 index c891928ae..000000000 --- a/app/views/post_regenerations/create.js.erb +++ /dev/null @@ -1 +0,0 @@ -Danbooru.notice("Post regenerated"); diff --git a/app/views/posts/partials/show/_options.html.erb b/app/views/posts/partials/show/_options.html.erb index 852a55205..17c4df489 100644 --- a/app/views/posts/partials/show/_options.html.erb +++ b/app/views/posts/partials/show/_options.html.erb @@ -88,6 +88,6 @@ <% end %> <% if policy(post).regenerate? %> -
  • <%= link_to "Regenerate image", post_regenerations_path(post_id: post.id, category: "resizes"), remote: true, method: :post, "data-confirm": "This will regenerate the posts's thumbnail images. Are you sure?" %>
  • +
  • <%= link_to "Regenerate image", post_regenerations_path(post_id: post.id, category: "resizes"), method: :post, "data-confirm": "This will regenerate the posts's thumbnail images. Are you sure?" %>
  • <% end %> diff --git a/test/functional/post_regenerations_controller_test.rb b/test/functional/post_regenerations_controller_test.rb index b02e9efdd..1b546d186 100644 --- a/test/functional/post_regenerations_controller_test.rb +++ b/test/functional/post_regenerations_controller_test.rb @@ -4,21 +4,63 @@ class PostRegenerationsControllerTest < ActionDispatch::IntegrationTest context "The post regenerations controller" do setup do @mod = create(:moderator_user, name: "yukari", created_at: 1.month.ago) - as(@mod) do - @post = create(:post, source: "https://google.com", tag_string: "touhou") - end + @upload = assert_successful_upload("test/files/test.jpg", user: @mod) + @post = @upload.post end context "create action" do should "render" do post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" } - assert_response :success + + assert_redirected_to @post + assert_enqueued_jobs(1, only: RegeneratePostJob) end should "not allow non-mods to regenerate posts" do post_auth post_regenerations_path, create(:user), params: { post_id: @post.id, category: "iqdb" } assert_response 403 end + + context "for an IQDB regeneration" do + should "regenerate IQDB" do + mock_iqdb_service! + Post.iqdb_sqs_service.expects(:send_message).with("update\n#{@post.id}\n#{@post.preview_file_url}") + + post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" } + perform_enqueued_jobs + end + + should "log a mod action" do + post_auth post_regenerations_path, @mod, params: { post_id: @post.id, category: "iqdb" } + perform_enqueued_jobs + + assert_equal(@mod, ModAction.last.creator) + assert_equal("post_regenerate_iqdb", ModAction.last.category) + assert_equal("@#{@mod.name} regenerated IQDB for post ##{@post.id}", ModAction.last.description) + end + end + + context "for an image sample regeneration" do + should "regenerate missing thumbnails" do + @preview_file_size = @post.file(:preview).size + @post.storage_manager.delete_file(@post.id, @post.md5, @post.file_ext, :preview) + assert_raise(Errno::ENOENT) { @post.file(:preview) } + + post_auth post_regenerations_path, @mod, params: { post_id: @post.id } + perform_enqueued_jobs + + assert_equal(@preview_file_size, @post.file(:preview).size) + end + + should "log a mod action" do + post_auth post_regenerations_path, @mod, params: { post_id: @post.id } + perform_enqueued_jobs + + assert_equal(@mod, ModAction.last.creator) + assert_equal("post_regenerate", ModAction.last.category) + assert_equal("@#{@mod.name} regenerated image samples for post ##{@post.id}", ModAction.last.description) + end + end end end end